Menu

CSS 미디어 쿼리: 브레이크포인트, min-width, max-width

미디어 쿼리는 최소 화면 너비, 다크 색상 테마, 마우스 포인터 같은 조건이 참일 때만 CSS를 적용해요. @media 문법, 모바일 우선 브레이크포인트, 범위 문법, prefers-color-scheme, JavaScript의 matchMedia, 컨테이너 쿼리를 알아봐요.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

예제 하나로 보는 미디어 쿼리

미디어 쿼리는 CSS를 조건으로 감싸요. @media (min-width: 600px) 안의 규칙은 뷰포트가 최소 600px 너비인 동안에만 적용돼요.

미리보기는 프레임이고, 그 안의 미디어 쿼리는 화면이 아니라 프레임을 측정해요. 데스크톱에서는 이 글의 열 정도 너비라서 보통 600px이 넘고, 상자가 파란색이에요. 프레임이 600px 아래로 떨어질 만큼 브라우저 창을 좁히면 주황색으로 바뀌고, 상자 아래 줄이 프레임 너비를 실시간으로 보여 줘요. 휴대폰에서는 프레임이 이미 좁아서 주황색 버전이 보여요.

@media 문법

@media (min-width: 600px) { ... }                        /* one condition */
@media (min-width: 600px) and (max-width: 899px) { ... } /* both must be true */
@media (max-width: 599px), print { ... }                 /* either one (comma = or) */
@media not print { ... }                                 /* negation */
@media screen and (orientation: landscape) { ... }       /* media type plus a feature */
@media (width >= 600px) { ... }                          /* range syntax */
@media (600px <= width < 900px) { ... }                  /* a range with both ends */

and는 양쪽에 공백이 필요해요. (min-width: 600px)and(max-width: 900px)는 잘못된 코드라서 쿼리 전체가 무시돼요. 범위 문법(width >= 600px)은 최신 Chrome, Firefox, Safari에서 지원하고, 특히 "이하가 아니라 미만"을 쓸 때 min-width보다 읽기 쉬워요.

가장 많이 쓰게 될 기능이에요.

기능일치하는 때예시
min-width / width >=뷰포트가 최소 이만큼 넓을 때(min-width: 768px)
max-width / width <=뷰포트가 최대 이만큼 넓을 때(max-width: 767px)
orientationportrait(세로가 더 김) 또는 landscape(orientation: landscape)
hover주 포인터가 hover할 수 있음(hover) 또는 없음(none, 대부분의 터치 화면)(hover: hover)
pointer주 포인터가 fine(마우스) 또는 coarse(손가락)(pointer: coarse)
prefers-color-scheme사용자가 dark나 light 테마를 골랐을 때(prefers-color-scheme: dark)
prefers-reduced-motion사용자가 시스템에 움직임을 줄여 달라고 했을 때(prefers-reduced-motion: reduce)
print (미디어 타입)페이지를 인쇄하거나 PDF로 저장할 때@media print

모바일 우선: min-width 브레이크포인트

휴대폰 레이아웃을 기본 CSS로 쓰고, 공간이 커질수록 레이아웃을 바꾸는 min-width 쿼리를 더하세요. 각 쿼리는 바뀌는 것만 적으면 돼요.

넓은 데스크톱 창에서는 미리보기가 720px을 넘어서 열 세 개가 보이고, grid 아래 줄이 너비와 열 수를 보여 줘요. 창을 좁히면 720px 아래에서 두 개로, 480px 아래에서 하나로 줄어요. 두 쿼리의 순서가 중요해요. 넓은 화면에서는 둘 다 참이고 나중 것이 이기니, min-width 쿼리는 작은 것부터 큰 것 순으로 써요. (max-width 쿼리는 반대로 큰 것부터예요.)

브레이크포인트 고르기

공식 목록은 없어요. 흔히 쓰는 값과 보통 구분하는 기기예요.

브레이크포인트보통
min-width: 640px가로 모드의 큰 휴대폰, 작은 태블릿
min-width: 768px세로 모드의 태블릿
min-width: 1024px가로 모드의 태블릿, 작은 노트북
min-width: 1280px데스크톱

더 좋은 방법이 있어요. 좁은 레이아웃에서 시작해서 뭔가 어색해질 때까지(줄이 너무 길거나 카드가 너무 넓을 때까지) 창을 넓히고, 거기에 브레이크포인트를 두세요. 대부분의 페이지는 두세 개면 충분해요. 아예 필요 없을 때도 많아요. grid의 repeat(auto-fit, minmax(200px, 1fr)), flex-wrap, clamp()는 연속적으로 적응해요.

모든 페이지에 viewport meta 태그가 필요해요

<head>에 이 태그가 없으면 휴대폰 브라우저는 화면이 약 980px 너비인 것처럼 페이지를 배치한 다음 축소해서, min-width: 480px 쿼리가 항상 참이 되고 휴대폰 레이아웃은 절대 보이지 않아요.

<meta name="viewport" content="width=device-width, initial-scale=1">

meta viewport 페이지에서 모든 값을 설명해요.

prefers-color-scheme으로 다크 모드

prefers-color-scheme은 운영체제의 라이트나 다크 설정을 따라요. 가장 깔끔한 방법은 색을 CSS 변수에 두고 쿼리 안에서는 변수만 바꾸는 거예요.

이 미리보기에서는 시스템이 다크 모드여도 쿼리가 false를 출력할 수 있어요. Chrome은 이런 sandbox 프레임에 시스템 설정을 전달하지 않기 때문이에요. 버튼은 같은 변수를 직접 바꾸는데, 사이트의 테마 전환 버튼도 이렇게 동작해요. :root[data-theme]는 쿼리 안의 단순한 :root보다 명시도가 높아서 사용자의 선택이 시스템 설정보다 우선해요. 쿼리가 시스템을 따라가는 모습을 보려면 예제를 파일로 저장해서 열어 보세요.

스크립트는 미디어 쿼리의 나머지 절반을 보여 줘요. matchMedia()는 같은 쿼리를 JavaScript에서 실행해서 지금 일치하는지 돌려주고, 답이 바뀌면 change 이벤트를 발생시켜요. 터치 기기에서 메뉴를 다르게 여는 것처럼 스타일만이 아니라 동작이 화면에 따라 달라질 때 쓰세요.

움직임도 같은 방식이에요. 크거나 반복되는 애니메이션은 애니메이션 페이지에서 보여 주듯 prefers-reduced-motion 검사로 감싸세요.

컨테이너 쿼리: 컴포넌트가 결정해야 할 때

미디어 쿼리는 뷰포트만 알아요. 같은 페이지에서 넓은 메인 열과 좁은 사이드바에 모두 놓이는 카드는 대신 자기 공간을 알아야 해요. 그게 컨테이너 쿼리예요. 부모에 container-type: inline-size를 표시하고, 같은 조건으로 @container를 쓰세요.

회색 상자의 모서리를 끌어서 크기를 바꿔 보세요. 카드는 창 크기와 상관없이 상자 너비 360px에서 레이아웃을 바꿔요.

처음 480px에서는 그림이 텍스트 옆에 있어요. 상자를 376px(콘텐츠 360px에 양쪽 padding 8px씩)보다 좁게 끌면 그림이 텍스트 위로 올라가요. 컨테이너 쿼리는 모든 최신 주요 브라우저에서 동작해요.

인쇄용 스타일

@media print는 페이지를 인쇄하거나 PDF로 저장할 때만 적용돼요. 내비게이션과 버튼을 숨기고, 흰 배경에 어두운 글자를 쓰세요.

@media print {
  nav, .ad, button { display: none; }
  body { color: black; background: white; }
  a::after { content: " (" attr(href) ")"; } /* print the URL after each link */
}

자주 하는 실수

  • viewport meta 태그 없음. 휴대폰이 넓은 레이아웃 뷰포트를 보고해서 작은 화면용 쿼리가 절대 일치하지 않아요.
  • 잘못된 순서의 쿼리. 같은 선택자에 참인 쿼리가 둘이면 나중 것이 이겨요. min-width 쿼리는 작은 것부터 큰 것 순으로 두세요.
  • 겹치거나 비는 경계. max-width: 768px와 min-width: 768px는 정확히 768px에서 둘 다 일치해요. 한쪽에 767px를 쓰거나 범위 문법 (width < 768px)와 (width >= 768px)를 쓰세요.
  • and 뒤에 공백 없음. and(는 잘못된 코드라서 쿼리가 조용히 버려져요.
  • 데스크톱 창 크기만 바꿔서 테스트하기. 실제 휴대폰이나 휴대폰의 뷰포트, 픽셀 비율, 터치를 적용하는 브라우저의 기기 모드로도 확인하세요.
  • 너무 많은 브레이크포인트. 컴포넌트마다 따로 필요하다면 grid auto-fit, flex-wrap, 컨테이너 쿼리를 대신 써 보세요.

자주 묻는 질문

CSS에서 미디어 쿼리란 무엇인가요?

기기나 창에 대한 조건이 참일 때만 안쪽의 CSS를 적용하는 규칙이에요. @media (min-width: 600px) { ... }는 뷰포트가 최소 600px 너비일 때만 스타일을 적용하고, 이렇게 한 페이지가 휴대폰부터 데스크톱까지 적응해요.

min-width와 max-width 미디어 쿼리 중 무엇을 써야 하나요?

대부분의 사이트는 모바일 우선으로 써요. 기본 CSS는 작은 화면용이고, 화면이 커지면 min-width 쿼리가 레이아웃을 더해요. max-width 쿼리는 데스크톱 레이아웃에서 시작하는 반대 방식이에요. 어느 쪽이든 되지만, 같은 요소에 둘을 섞으면 경계에서 겹치거나 빈틈이 생겨요.

표준 미디어 쿼리 브레이크포인트는 무엇인가요?

공식 표준은 없어요. 흔히 640px, 768px, 1024px, 1280px 근처를 고르지만, 더 좋은 규칙은 내 레이아웃이 어색해지기 시작하는 곳에 브레이크포인트를 두고 개수를 적게 유지하는 거예요.

휴대폰에서 미디어 쿼리가 동작하지 않는 이유는 무엇인가요?

가장 흔한 원인은 viewport meta 태그가 빠진 거예요. <meta name="viewport" content="width=device-width, initial-scale=1">이 없으면 모바일 브라우저가 페이지를 약 980px 너비로 간주해서 작은 너비 쿼리가 절대 일치하지 않아요. 쿼리가 덮어쓰려는 규칙보다 뒤에 있는지도 확인하세요.

다크 모드용 미디어 쿼리는 어떻게 쓰나요?

@media (prefers-color-scheme: dark) { ... }를 써요. 사용자의 운영체제나 브라우저가 다크 테마로 설정되어 있으면 일치하고, 그 안에서 색이나 CSS 변수를 덮어쓸 수 있어요.

미디어 쿼리와 컨테이너 쿼리는 무엇이 다른가요?

미디어 쿼리는 뷰포트(창 전체)를 검사해요. @container로 쓰는 컨테이너 쿼리는 container-type: inline-size로 표시한 부모 요소의 크기를 검사해요. 같은 페이지에서 넓은 곳과 좁은 곳에 모두 나오는 컴포넌트에는 컨테이너 쿼리를 쓰세요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기