미디어 쿼리로 만드는 반응형 디자인
meta 태그 하나가 없으면 많은 휴대전화가 화면이 훨씬 넓은 것처럼(MDN은 980픽셀을 예로 듭니다) 페이지를 배치한 뒤 줄여 버려서, 휴대전화용 미디어 쿼리가 아예 작동하지 않습니다.
페이지 하나, 모든 화면
반응형 디자인은 모바일 사이트를 따로 만들지 않고, 좁은 휴대전화부터 넓은 모니터까지 어느 화면에서나 맞춰 바뀌는 페이지 하나를 만드는 것입니다. 바탕에는 생각이 세 가지 있습니다. 고정 너비 대신 유연한 너비로 만든 배치, 컨테이너 안에서 크기가 바뀌는 그림과 영상, 그리고 배치가 더 버티지 못하는 지점에서 배치를 고치는 미디어 쿼리입니다. 앞의 두 단원에서 줄바꿈되는 카드와 auto-fill 열로 본 것처럼, 플렉스박스와 그리드가 이미 많은 일을 해 줍니다.
viewport meta 태그
예전 사이트는 데스크톱용으로 만들어졌기 때문에, 많은 휴대전화는 화면보다 넓은 가상 뷰포트(MDN은 980픽셀을 예로 듭니다)에 페이지를 그린 뒤 줄여서 보여 줍니다. 화면에 맞춰 바뀌도록 만든 페이지에는 이것이 방해가 됩니다. 브라우저가 화면을 980픽셀로 알고 있으니 600픽셀보다 좁을 때 켜져야 할 미디어 쿼리가 절대 작동하지 않습니다. head에 <meta name="viewport" content="width=device-width">를 넣으면 브라우저가 CSS 픽셀로 잰 기기의 실제 너비를 씁니다. user-scalable=no나 낮은 maximum-scale은 절대 넣지 마세요. MDN은 확대를 막으면 저시력인 사람이 내용을 읽을 수 없게 된다고 경고하고, WCAG 1.4.4는 글자를 200퍼센트까지 키울 수 있기를 요구합니다.
유연한 너비와 그림
휴대전화에서 옆으로 스크롤이 생기는 가장 흔한 원인은 고정 너비입니다. width보다 max-width를 쓰세요. 페이지를 감싼 요소에 max-width: 70rem을 주면 작은 화면에서는 꽉 차고 큰 화면에서는 더 커지지 않습니다. 그림은 기본으로 원래 픽셀 크기를 지키므로, 1200픽셀 사진은 390픽셀 화면 밖으로 넘칩니다. img { max-width: 100%; height: auto; }를 주면 비율을 유지한 채 컨테이너에 맞게 줄어듭니다. WCAG 1.4.10(리플로우)은 너비 320 CSS 픽셀에서도 두 방향으로 스크롤하지 않고 내용을 쓸 수 있기를 요구하므로, 창 너비를 320픽셀로 줄여 확인하는 습관을 들이면 좋습니다.
미디어 쿼리
미디어 쿼리는 조건이 맞을 때만 적용되는 규칙을 감쌉니다. @media (min-width: 600px) { ... }는 뷰포트 너비가 600픽셀 이상일 때 안의 규칙을 적용합니다. 보통은 모바일 우선으로 씁니다. 좁은 화면용 기본 스타일(대개 한 열로 쌓는 가장 단순한 모습)을 먼저 쓰고, 공간이 넓어질 때 배치를 바꾸는 min-width 쿼리를 더합니다. 분기점은 인기 있는 기기 크기를 짐작해 고르지 말고 내 내용이 어색해지기 시작하는 지점에 둡니다. 해마다 새 화면 크기가 나오기 때문입니다. 40em처럼 em으로 분기점을 쓰면 독자가 글자를 키웠을 때도 반응합니다.
/* Base: one column for narrow screens */
.cols { display: grid; gap: 16px; }
/* From 600px: two columns */
@media (min-width: 600px) {
.cols { grid-template-columns: 1fr 1fr; }
}
/* From 960px: a sidebar layout */
@media (min-width: 960px) {
.cols { grid-template-columns: 240px 1fr 1fr; }
}쿼리가 물을 수 있는 다른 것
미디어 쿼리는 너비 말고도 여러 조건을 검사합니다. 독자의 설정을 묻는 기능은 Media Queries Level 5에 정의되어 있습니다. (prefers-color-scheme: dark)는 독자가 운영 체제에서 어두운 테마를 골랐을 때 맞아서, 어두운 색을 저절로 보여 줄 수 있습니다. (prefers-reduced-motion: reduce)는 독자가 움직임을 줄여 달라고 설정했을 때 맞습니다. 애니메이션 때문에 어지러움을 느끼는 사람이 많으므로, 이 쿼리 안에서는 큰 움직임과 패럴랙스 효과를 끕니다. Level 4에 있는 (hover: hover)는 주 포인터가 마우스처럼 올려놓을 수 있는지 알려 주는데, 터치 화면은 그럴 수 없습니다. print는 메뉴를 숨기는 식으로 종이에 인쇄할 때의 모양을 정합니다. 끝으로 clamp()는 쿼리 없이 크기를 부드럽게 조절합니다. font-size: clamp(1.5rem, 4vw, 2.5rem)는 화면을 따라 커지되 1.5rem보다 작아지거나 2.5rem보다 커지지 않습니다.
| 반응형 디자인 | 모든 화면에 맞춰 바뀌는 페이지 하나 |
| 뷰포트 | 브라우저에서 페이지가 보이는 영역 |
| width=device-width | 가상의 980px가 아니라 실제 기기 너비 사용 |
| 미디어 쿼리 | @media (조건) { 규칙 } |
| 모바일 우선 | 좁은 화면용 기본 스타일 다음에 min-width 쿼리 |
| 분기점 | 배치가 바뀌는 너비 |
| prefers-reduced-motion | 독자가 애니메이션을 줄여 달라고 설정함 |
| clamp() | 최소와 최대 사이에서 정해지는 값 |
- viewport meta 태그가 없으면 휴대전화용 미디어 쿼리가 작동하지 않는 이유는?
- 휴대전화가 넓은 가상 너비로 페이지를 배치해서
- 휴대전화는 CSS를 무시해서
- 미디어 쿼리에는 JavaScript가 필요해서
@media (min-width: 600px)는 언제 적용될까요?- 뷰포트가 600px 이상일 때
- 600px 미만일 때
- 정확히 600px일 때만
- 모바일 우선이란?
- 좁은 화면용 기본 스타일을 쓰고 min-width 쿼리를 더함
- 휴대전화 사이트를 먼저, 데스크톱 사이트를 나중에
- 휴대전화에서 내용을 숨김
- 큰 그림이 좁은 화면 밖으로 넘치지 않게 하는 규칙은?
- img { max-width: 100%; height: auto; }
- img { width: 1200px; }
- img { display: none; }
- WCAG 1.4.10 리플로우는 몇 CSS 픽셀 너비에서 두 방향 스크롤 없이 쓸 수 있기를 요구할까요?
- user-scalable=no를 쓰면 안 되는 이유는?
- 확대를 막아 저시력인 사람이 읽을 수 없게 됨
- 미디어 쿼리가 깨짐
- 올바른 HTML이 아님
- 분기점은 어떻게 고를까요?
- 내 내용이 어색해지기 시작하는 곳
- 인기 휴대전화 목록에서
- 항상 768px
- 애니메이션을 줄여 달라고 설정한 독자에게 맞는 쿼리는?
- (prefers-reduced-motion: reduce)
- (hover: none)
- (orientation: portrait)
- rem이 16px이고 화면 너비가 1600px일 때 font-size: clamp(1.5rem, 4vw, 2.5rem)는?
- 분기점을 em으로 쓰는 이유는?
- 독자가 글자를 키우면 함께 반응해서
- 미디어 쿼리에는 em이 필수라서
- 더 빨리 뜨서
- viewport meta 태그를 넣고, 확대는 막지 않습니다.
- 유연한 너비, width 대신 max-width, img { max-width: 100%; height: auto; }.
- 내용에 맞는 분기점에 min-width 쿼리로 모바일 우선. prefers-color-scheme, prefers-reduced-motion, print, clamp()도 있습니다.