
CSS로 폭만 줄이는 것으로는 부족한 경우가 있습니다. 폰에서는 아예 다른 구성을 보여줘야 할 때입니다. 이 글은 화면 크기를 자바스크립트에서 재서 구성을 나눈 방법입니다.
CSS만으로 안 되는 경우
대부분은 CSS의 미디어 쿼리로 충분합니다. 폭이 좁으면 열을 줄이고 글자를 키우면 됩니다. 하지만 데이터 순서 자체가 달라져야 할 때는 CSS로 못 합니다.
제 경우가 그랬습니다. 데스크톱에서는 카드를 두 줄로 놓으려고 순서를 섞는데, 폰에서는 한 줄이라 섞으면 안 됩니다. 화면을 그리기 전에 판단이 필요했습니다.
function isGpMovieMobileLayout(){ return !!(window.matchMedia && window.matchMedia('(max-width:800px)').matches);}짧지만 세 가지가 들어 있습니다. matchMedia가 있는지 먼저 확인합니다. 아주 오래된 브라우저에는 없습니다. 앞의 !!는 결과를 참·거짓으로 확실히 만들기 위한 것입니다.
그리고 기준을 CSS와 같은 문법으로 씁니다. window.innerWidth로 재는 방법도 있지만, 그러면 CSS와 자바스크립트가 서로 다른 기준을 쓰게 됩니다. 게다가 innerWidth는 세로 스크롤바 폭까지 포함한 값이라, 스크롤바를 뺀 폭이 필요하면 값을 따로 골라야 합니다. 아래 ‘기준을 숫자로 맞추기’ 표에서 정리합니다.
matchMedia가 돌려주는 것
MDN 문서에 따르면 matchMedia(문자열)은 입력한 미디어 쿼리를 해석해 MediaQueryList 객체를 새로 돌려줍니다. 이 객체로 지금 조건에 맞는지 확인하거나, 시간이 지나며 조건이 바뀌는지 지켜볼 수 있습니다. 위 함수가 끝에 .matches를 붙인 이유가 이것입니다. 같은 문서에서 이 기능은 2015년 7월부터 주요 브라우저에서 쓸 수 있는 Baseline ‘널리 사용 가능’ 단계라고 적고 있습니다.
| 쓰는 곳 | 하는 일 | 언제 맞나 |
|---|---|---|
matches | 지금 조건에 맞으면 true, 아니면 false | 부른 그 순간 한 번의 확인입니다. |
change 이벤트 | 조건에 맞기 시작하거나 맞지 않게 될 때 알려 줍니다. | 계속 지켜봐야 할 때 씁니다. |
또 하나 눈여겨볼 점은 괄호입니다. MDN 예시에는 matchMedia("(width <= 600px)")처럼 조건마다 괄호를 씌운 형태가 유효하다고 나옵니다. 괄호 없이 "width < 600px"로 쓰면 유효하지 않다고 합니다. screen, and, not 같은 미디어 유형과 논리 연산자에는 괄호가 필요 없습니다. 이 글의 함수가 쓴 (max-width:800px)도 같은 규칙에 따라 괄호로 묶여 있습니다.

기준을 한 곳에 두기
여기서 실수했던 게 있습니다. CSS에는 800px, 자바스크립트에는 768을 썼습니다. 그랬더니 780px 근처에서 화면이 이상하게 나왔습니다. CSS는 폰으로 보는데 자바스크립트는 데스크톱으로 보는 구간이 생긴 겁니다.
재현이 잘 안 돼서 한참 헤맸습니다. 창을 특정 크기로 만들어야만 나타났기 때문입니다.
어긋나는 구간을 숫자로 보면
위에서 말한 실수를 숫자로 풀어 보면 이렇습니다. CSS는 max-width:800px, 자바스크립트는 폭이 768 이하일 때만 폰으로 봤다고 가정합니다. W3C 미디어 쿼리 규격은 max-가 붙은 조건이 “이하”, 즉 그 값을 포함하는 비교라고 설명합니다. 그래서 CSS 기준으로는 800px 폭도 폰입니다. 아래 폭은 구간을 보여 주려고 고른 예시 값입니다.
| 창 폭(예시) | CSS(800 이하) | 자바스크립트(768 이하) | 결과 |
|---|---|---|---|
| 700px | 폰 | 폰 | 일치 |
| 768px | 폰 | 폰 | 일치 |
| 780px | 폰 | 데스크톱 | 어긋남 |
| 800px | 폰 | 데스크톱 | 어긋남 |
| 801px | 데스크톱 | 데스크톱 | 일치 |
769px부터 800px까지가 어긋나는 구간입니다. 글 앞에서 본 780px 현상이 정확히 이 안에 들어갑니다. 숫자를 두 곳에 따로 적으면 이런 틈이 생기고, 한 곳에만 적으면 생길 수 없습니다.
기준을 숫자로 맞추기
폭을 재는 방법은 하나가 아닙니다. 문서에 적힌 내용만 모으면 다음과 같습니다.
| 방법 | 스크롤바 | 참고 |
|---|---|---|
window.innerWidth | 세로 스크롤바가 있으면 그 폭을 포함 | MDN: 레이아웃 뷰포트의 폭이며 읽기 전용 정수입니다. |
document.documentElement.clientWidth | 스크롤바를 뺀 폭 | MDN이 스크롤바와 테두리를 뺀 폭이 필요할 때의 방법으로 안내합니다. |
미디어 쿼리의 width | 화면에 그려지는 스크롤바를 포함 | W3C: 연속 매체에서는 뷰포트 폭이며 CSS 픽셀 기준입니다. |
결국 CSS 미디어 쿼리의 width와 innerWidth는 둘 다 스크롤바를 포함하는 쪽이라 같은 기준에 가깝습니다. 그런데도 이 글이 matchMedia를 고른 이유는 숫자를 비교하는 코드를 따로 쓰지 않고, CSS에 적은 조건 문자열을 그대로 가져다 쓸 수 있기 때문입니다. 기준 문자열을 한 곳에 두고 CSS와 자바스크립트가 같이 읽게 하면 어긋남이 생길 자리가 없습니다.
범위 문법으로 쓰기
W3C 미디어 쿼리 레벨 4 규격(2026년 2월 19일자 후보 권고 초안)은 (width <= 800px)처럼 부등호로 쓰는 범위 문법을 정의합니다. 이 문법에서 (max-width: 40em)은 (width <= 40em)과 같고, min-은 >=와 같습니다. 두 값 사이도 (400px <= width <= 700px)처럼 쓸 수 있습니다. 다만 같은 규격은 이 문법이 min-·max- 접두어보다 새롭고 덜 지원된다고 적어 두었습니다. 그래서 오래된 환경을 고려하는 글에서는 접두어 형태로 써 두었고, 두 형태는 같은 뜻입니다.
화면을 돌리면 다시 계산해야 한다
폰을 가로로 돌리면 폭이 바뀝니다. 그런데 이 함수는 부를 때 한 번만 판단합니다. 이미 그려진 화면은 그대로입니다.
그래서 크기 변경을 감지해서 다시 그리도록 했습니다. 다만 크기 변경은 드래그하는 동안 수십 번 발생하니, 잠깐 기다렸다가 한 번만 처리합니다.
var timer = null;window.addEventListener('resize', function(){ clearTimeout(timer); timer = setTimeout(function(){ redraw(); }, 200); // 멈춘 뒤 한 번만});MDN의 resize 이벤트 문서에 따르면 이 이벤트는 window 객체에서만 발생합니다. 다른 요소에 핸들러를 달아도 받지 못하고, 요소의 크기 변화는 ResizeObserver를 쓰라고 안내합니다. 같은 문서는 이 이벤트가 일부 용도에서는 너무 많이 발생할 수 있다고 경고합니다. 위 코드의 200ms 지연은 그 문제를 줄이려는 선택이고, 200이라는 숫자에 특별한 근거는 없습니다.
change 이벤트로 대신하기
크기가 계속 바뀌는 모든 순간이 아니라 “폰이냐 아니냐”가 바뀌는 순간만 필요하다면, 미디어 쿼리 객체의 change 이벤트가 더 맞을 수 있습니다. MDN은 이 이벤트를 조건에 맞기 시작하거나 맞지 않게 될 때 발생한다고 설명합니다.
var mql = window.matchMedia('(max-width:800px)');
mql.addEventListener('change', function(){ redraw(); });
| 방식 | 다시 그리는 때 | 잘 맞는 경우 |
|---|---|---|
resize + 지연 | 창 크기가 바뀔 때마다(멈춘 뒤 한 번) | 폭 값 자체가 필요한 계산이 있을 때 |
change 이벤트 | 폰 조건이 바뀌는 순간에만 | 폰/데스크톱 구성만 나누면 될 때 |
이 글의 화면은 폰과 데스크톱 두 가지 구성만 나누므로 change 쪽이 더 단순할 수 있습니다. 다만 이 방식으로 실제 기기를 돌려 보지는 못했으므로, 적용하기 전에 본인 환경에서 한 번 확인하시길 권합니다.

먼저 CSS로 되는지 본다
지금 와서 보면, 자바스크립트로 화면을 나누는 건 마지막 수단입니다. CSS로 되는 건 CSS로 하는 게 훨씬 안정적입니다. 브라우저가 알아서 처리하고, 크기가 바뀌어도 저절로 따라갑니다.
자바스크립트가 필요한 건 데이터 순서나 구조 자체가 달라질 때뿐입니다. 색이나 크기 정도면 CSS로 충분합니다.
적용 전에 확인할 목록
- CSS로 되는지부터: 열 수나 글자 크기만 달라지면 미디어 쿼리로 끝냅니다. 자바스크립트는 순서나 구조가 달라질 때만 씁니다.
- 기준 문자열은 한 곳에: 800이라는 숫자를 CSS와 자바스크립트에 따로 적지 않습니다.
- 괄호 확인:
matchMedia에 넘기는 조건은(조건)형태여야 합니다. - 다시 계산하는 때:
resize에 지연을 두거나change이벤트를 씁니다. - 폭을 직접 잴 때:
innerWidth는 스크롤바를 포함하고, 뺀 폭은documentElement.clientWidth로 얻습니다. - 실제 기기: 개발자 도구의 크기 조절만으로 끝내지 않고, 가능하면 폰과 태블릿으로 한 번씩 봅니다.
한계
800px이라는 숫자에 근거는 없습니다. 태블릿 세로 폭 근처라 잡았는데, 기기마다 달라서 애매한 크기에서는 어느 쪽으로도 어색할 수 있습니다.
그리고 실제 기기로 다 확인하지 못했습니다. 브라우저 개발자 도구의 화면 크기 조절로만 봤고, 아이패드나 폴더블 같은 기기에서는 어떻게 나오는지 모릅니다.
확인 자료
- MDN: Window.matchMedia() (확인: 2026-10-18)
- MDN: Window.innerWidth (확인: 2026-10-18)
- MDN: Window resize 이벤트 (확인: 2026-10-18)
- W3C: Media Queries Level 4 (확인: 2026-10-18)
위 문서는 브라우저 동작에 관한 일반 설명이며, 기기마다 실제 결과는 다를 수 있습니다.