안녕하세요! 프론트엔드 개발의 필수 관문이자 현대 웹 디자인의 핵심인 반응형 웹 디자인(Responsive Web Design)의 세계로 오신 것을 환영합니다!
스마트폰, 태블릿, 거대한 데스크톱 모니터... 이 모든 다양한 화면에서 웹사이트가 깨지지 않고 예쁘게 보이도록 만드는 마법의 주문이 바로 오늘 배울 미디어 쿼리(Media Queries)입니다. 실무에서 하루에도 수백 번씩 쓰게 될 이 중요한 기술을, 공식 문서의 내용을 바탕으로 제가 현업에서 얻은 노하우와 함께 아주 쉽게 풀어드릴게요. 자, 시작해 볼까요?
이전 페이지 (Overview: CSS layout) | 개요: CSS 레이아웃 | 다음 페이지 (Test your skills: Responsive design)
CSS 미디어 쿼리(Media Query)는 브라우저와 기기 환경이 여러분이 지정한 특정 규칙(예: "뷰포트(화면) 너비가 480픽셀보다 넓을 때")과 일치할 때만 특정 CSS를 적용할 수 있게 해 주는 기능입니다. 미디어 쿼리는 화면 크기에 따라 다른 레이아웃을 만들 수 있게 해 주므로 반응형 웹 디자인의 핵심 요소입니다. 하지만 그뿐만 아니라, 사용자가 마우스 대신 터치스크린을 사용하고 있는지 등 사이트가 실행되고 있는 기기 환경의 다양한 다른 조건들을 감지하는 데에도 사용될 수 있습니다.
이 레슨에서는 먼저 미디어 쿼리에 사용되는 기본 문법을 배우고, 이어서 기본적인 디자인이 어떻게 반응형으로 탈바꿈하는지 보여주는 예제를 통해 미디어 쿼리를 실제로 사용해 보겠습니다.
| 사전 준비 지식: | HTML로 콘텐츠 구조화하기, CSS 스타일링 기초, 기본 텍스트 및 폰트 스타일링, CSS 레이아웃 기초 개념에 대한 친숙함. |
| 학습 목표: |
|
가장 단순한 형태의 미디어 쿼리 문법은 다음과 같이 생겼습니다:
@media media-type and (media-feature-rule) {
/* 여기에 특정 조건에서만 작동할 CSS 규칙들을 적습니다 */
}
미디어 쿼리는 다음 세 가지 부분으로 구성됩니다:
{ }) 안의 CSS가 적용되기 위해 반드시 통과해야 하는 규칙이나 테스트(조건)입니다.여러분이 지정할 수 있는 미디어의 종류는 다음과 같습니다:
all: 모든 미디어 장치print: 프린터 (인쇄 미리보기 화면 등)screen: 컴퓨터 화면, 태블릿, 스마트폰 등 일반적인 스크린다음 미디어 쿼리는 페이지가 인쇄(print)될 때만 body의 글자 크기를 12pt로 설정합니다. 브라우저 화면으로 그냥 볼 때는 이 스타일이 전혀 적용되지 않습니다.
@media print {
body {
font-size: 12pt;
}
}
📝 참고사항 (Note):
여기서 말하는 미디어 타입은 파일 형식(MIME type)과는 다릅니다. 예전 CSS Level 3 명세에는 더 많은 미디어 타입(예: tv, tty 등)이 있었지만, 지금은 대부분 폐기되었으므로 사용을 피해야 합니다. 미디어 타입은 생략할 수 있으며, 생략할 경우 기본값인all(모든 미디어 타입)로 처리됩니다.
💡 강사의 실무 팁! (Print 미디어 쿼리)
display: none;) 코드를@media print { }안에 넣어두면 사용자들에게 사랑받는 웹사이트를 만들 수 있습니다!
미디어 타입을 지정한 후(또는 생략한 후), 규칙을 사용해 특정 미디어 특성(media feature)을 타겟팅할 수 있습니다.
다음 예제들은 다양한 미디어 쿼리를 어떻게 사용하는지 보여줍니다. 이 속성들이 어떻게 작동하는지 보려면 브라우저 창의 크기를 줄이거나 늘려보고, 모바일 기기를 가로/세로로 돌려보세요.
📝 참고사항 (Note):
실제 창을 줄이는 대신, 브라우저 개발자 도구의 '반응형 디자인 모드'(예: Chrome의 Device Toolbar, Firefox의 Responsive Design Mode)를 사용하면 다양한 스마트폰 기기의 화면 너비를 아주 쉽게 시뮬레이션할 수 있습니다.
우리가 반응형 디자인을 만들기 위해 가장 빈번하게, 그리고 가장 널리 지원되는 방식으로 감지하는 특성은 바로 뷰포트(화면) 너비입니다. width 미디어 특성을 사용하고 필요에 따라 min-(최소) 또는 max-(최대) 접두사를 붙여서, 뷰포트가 특정 너비 이상일 때, 이하일 때, 또는 정확히 그 너비일 때만 CSS를 적용할 수 있습니다.
이 특성들은 다양한 화면 크기에 반응하는 레이아웃을 만드는 핵심입니다. 예를 들어, 뷰포트 너비가 정확히 600픽셀일 때만 본문 글자 색상을 빨간색으로 바꾸고 싶다면 다음과 같이 작성합니다. (실무에선 정확한 픽셀 매칭은 거의 쓰지 않지만요!)
@media screen and (width: 600px) {
body {
color: red;
}
}
<p>
One November night in the year 1782, so the story runs, two brothers sat over
their winter fire...
</p>
위의 예제 코드를 실행하고 브라우저 너비를 천천히 조절해 보세요. 화면이 딱 600px이 되는 마법의 순간에 글씨가 빨간색으로 변하는 것을 볼 수 있습니다.
하지만 실무에서 반응형 디자인을 할 때는 특정 픽셀을 딱 맞추는 것보다, 최솟값(min)이나 최댓값(max)을 사용해 '범위'를 지정하는 것이 훨씬 유용합니다. 그래서 width나 height 단독으로는 거의 쓰이지 않습니다.
예를 들어, 뷰포트 너비가 600픽셀 이하(600픽셀을 포함하여 더 좁을 때)일 때 글자 색상을 파란색으로 만들고 싶다면 max-width를 사용합니다:
@media screen and (max-width: 600px) {
body {
color: blue;
}
}
브라우저 창을 600px 이하로 좁히면 위의 텍스트가 파란색으로 변하는 것을 확인할 수 있습니다. 모바일 화면을 타겟팅할 때 자주 쓰는 방식이죠!
테스트할 수 있는 다른 미디어 특성들도 많습니다. (최신 Level 4, 5 명세에 추가된 기능들은 아직 브라우저 지원이 완벽하지 않을 수 있습니다.) 모든 기능과 브라우저 지원 여부는 MDN의 미디어 쿼리 사용하기: 구문 페이지에서 전체 목록을 확인하실 수 있습니다.
지원율이 아주 좋은 또 다른 유용한 미디어 특성은 화면이 세로 방향(portrait)인지 가로 방향(landscape)인지 테스트할 수 있는 orientation입니다. 기기가 가로 방향일 때 본문 글자 색상을 바꾸려면 다음과 같이 작성합니다.
@media (orientation: landscape) {
body {
color: rebeccapurple;
}
}
일반적인 데스크톱 모니터는 대부분 가로 방향(landscape)이기 때문에 데스크톱에서는 잘 동작하지만, 스마트폰이나 태블릿에서는 기기를 눕혀야만 이 스타일이 적용됩니다. 가로 방향에서는 잘 어울리던 디자인이 모바일의 세로 방향(portrait) 화면에서는 답답하게 보일 수 있기 때문에, 이 특성을 사용해 세로 모드에 최적화된 레이아웃을 따로 만들어 주는 기법이 자주 쓰입니다.
Media Queries Level 4 명세에는 흥미로운 기능이 추가되었는데, 바로 사용자가 요소를 '호버(hover, 마우스 올리기)' 할 수 있는 능력이 있는지 테스트하는 hover 미디어 특성입니다. 쉽게 말해, 사용자가 마우스나 트랙패드 같은 '포인팅 장치'를 쓰고 있는지, 아니면 손가락(터치스크린)이나 키보드만 쓰고 있는지 알아내는 기능입니다. 터치스크린에서는 마우스를 올리는(hover) 개념이 없으니까요!
/* 마우스를 올릴 수 있는 기기(PC 등)에서만 이 hover 효과를 적용해라! */
@media screen and (hover: hover) {
body:hover {
color: white;
background: black;
}
}
위 예제는 마우스를 올릴 수 있는 기기에서만 호버 시 배경이 검은색, 글씨가 흰색으로 변하도록 합니다. 터치스크린 사용자에게는 호버로만 볼 수 있는 메뉴 같은 것을 애초에 기본으로 다 펼쳐서 보여주고, 마우스 사용자에게만 마우스를 올렸을 때 메뉴가 나타나도록 하는 등 아주 유연한 인터페이스 설계가 가능해집니다.
또한 Level 4에는 pointer 미디어 특성도 있습니다. 이는 none(포인터 없음, 키보드나 음성 제어), fine(마우스처럼 좁은 영역을 정밀하게 클릭 가능), coarse(손가락 터치처럼 클릭 범위가 뭉툭함)라는 세 가지 값을 가집니다.
예를 들어 pointer: coarse (터치스크린)인 것을 감지하면, 사용자가 손가락으로 누르기 편하도록 버튼 크기나 여백을 훨씬 큼직큼직하게(hit areas를 넓게) 키워주는 훌륭한 반응형 UX를 구현할 수 있습니다.
💡 강사의 실무 팁! (Touch 기기 대응)
예전에는 기기가 터치스크린인지 아닌지 자바스크립트로 복잡하게 알아내야 했지만, 이제는 CSS만으로@media (pointer: coarse)를 써서 터치 기기용으로 버튼을 키워주거나,@media (hover: hover)를 써서 터치 기기에서 오작동하는:hover효과를 아예 꺼버릴 수 있습니다. 정말 강력해진 기능이죠!
반응형 작업 시 가장 흔한 경우 중 하나는 뷰포트 너비가 '특정 값과 특정 값 사이'에 있을 때를 지정하는 것입니다.
@media (min-width: 30em) and (max-width: 50em) {
/* 너비가 30em 이상, 50em 이하일 때 적용할 CSS */
}
최신 CSS에서는 이 코드를 읽기 훨씬 편한 "범위(range)" 구문으로 작성할 수 있습니다. 수학 기호랑 똑같아서 직관적이죠!
@media (30em <= width <= 50em) {
/* 너비가 30em 이상, 50em 이하일 때 적용할 CSS */
}
두 경우 모두 뷰포트 너비가 30em에서 50em 사이일 때 괄호 안의 스타일이 적용됩니다.
여러분이 배운 다양한 미디어 쿼리 특성들을 조합(combine)하거나, '이 중 하나라도 맞으면 적용해라'라는 식의 리스트를 만들 수도 있습니다.
미디어 특성을 결합하려면 이전에 미디어 타입과 특성을 묶을 때 썼던 것처럼 and 연산자를 사용하면 됩니다. 예를 들어, 우리는 width와 orientation을 동시에 테스트하고 싶습니다. 뷰포트가 최소 600픽셀 이상이면서(AND) 동시에 가로 모드(landscape)일 때만 본문 글자를 파란색으로 만들고 싶다면 이렇게 씁니다.
@media screen and (width >= 600px) and (orientation: landscape) {
body {
color: blue;
}
}
(화면을 넓게 펴고 가로로 늘려야만 글씨가 파란색으로 변합니다! 둘 중 하나라도 조건이 안 맞으면 적용되지 않습니다.)
주어진 조건들 중 '단 하나라도 맞으면(OR)' 스타일을 적용하고 싶다면 쉼표(,)를 사용하여 쿼리들을 나열하면 됩니다. 아래 예제에서는 뷰포트 너비가 최소 600픽셀 이상이거나(OR) 기기가 가로 모드일 때 텍스트가 파란색이 됩니다. 둘 중 하나만 참이어도 쿼리가 통과됩니다!
@media screen and (width >= 600px), screen and (orientation: landscape) {
body {
color: blue;
}
}
not 연산자를 사용하면 미디어 쿼리 전체를 부정(부정 논리)할 수 있습니다. 즉, 조건의 의미를 완전히 반대로 뒤집는 것이죠. 다음 예제에서는 뷰포트 너비가 600픽셀 이상이 '아닐 때만(NOT)' 텍스트가 파란색이 됩니다. (즉, 600px 미만일 때 파란색이 된다는 뜻이죠.)
@media not (width >= 600px) {
body {
color: blue;
}
}
not을 범위와 함께 쓰면 재미있는 논리가 완성됩니다.
@media (not (width < 600px)) and (not (width > 1000px)) {
body {
color: blue;
}
}
이 코드는 "너비가 600px 미만이 아니고(AND) 너비가 1000px 초과가 아닐 때" 적용됩니다. 풀어서 말하면 뷰포트 너비가 600px에서 1000px 사이일 때만 파란색이 된다는 뜻이며, 이는 앞서 배운 (600px <= width <= 1000px)와 완전히 똑같은 결과를 냅니다.
반응형 디자인 초창기에는 많은 디자이너와 개발자들이 인기 있는 특정 핸드폰이나 태블릿(예: 아이폰 사이즈인 320px, 아이패드 사이즈인 768px 등)의 화면 크기 목록을 뽑아놓고, 그 특정 뷰포트 크기에 딱 들어맞게 디자인을 쪼개곤 했습니다.
하지만 이제는 이런 방식을 쓰면 안 됩니다! 요즘은 너무나도 다양한 크기를 가진 수많은 종류의 기기들이 쏟아져 나오고 있어서, 특정 기기 크기만 타겟팅하는 것은 완전히 불가능해졌기 때문입니다.
대신에, 이제는 디자인을 유동적으로 만들다가 화면을 쭉쭉 줄이거나 늘려봤을 때 디자인이나 레이아웃이 어딘가 깨지거나 어색해지는 지점(content starts to break)에서 미디어 쿼리를 추가하는 것이 훨씬 더 좋은 접근 방식입니다!
글줄이 너무 길어져서 읽기 힘들어지거나, 사이드바가 너무 찌그러져서 못생겨지는 바로 그 순간! 그 지점이 바로 미디어 쿼리를 추가해서 레이아웃을 공간에 맞게 예쁘게 바꿔줘야 할 타이밍입니다. 이렇게 하면 기기의 정확한 픽셀 크기가 320px이든 412px이든 1000px이든 상관없이 모든 구간(range)에서 디자인이 완벽하게 대응하게 됩니다.
미디어 쿼리가 투입되어 레이아웃이 변하는 이 마법의 지점들을 우리는 브레이크포인트(breakpoints, 분기점)라고 부릅니다.
브레이크포인트를 어디에 두어야 할지 알아낼 때는 Firefox DevTools의 반응형 디자인 모드나 Chrome의 Device Toolbar를 사용하는 것이 정말 유용합니다. 화면(뷰포트) 크기를 드래그해서 자유자재로 늘렸다 줄였다 하면서, 어느 시점에 레이아웃이 뭉개지는지, 어느 시점에 미디어 쿼리를 넣어야 디자인이 깔끔해질지 눈으로 직접 확인하며 작업할 수 있거든요.

반응형 디자인을 구축할 때는 크게 두 가지 접근 방식을 취할 수 있습니다.
max-width)를 추가해서 요소들을 구겨 넣거나 숨기는 방식입니다.min-width)를 추가해서 복잡한 레이아웃(다단, 사이드바 등)을 덧붙이는 방식입니다.결론부터 말씀드리면, 이 두 번째 방식인 '모바일 우선(Mobile-first)' 반응형 디자인이 거의 항상 최고의, 그리고 가장 권장되는 접근 방식입니다.
가장 작은 스마트폰 기기를 위한 화면은 종종 사이드바 같은 거추장스러운 것 없이 콘텐츠가 세로로 일렬로 떨어지는(single column) 형태입니다. 즉, 정상 흐름(normal flow) 그대로죠! 이는 여러분이 모바일 기기를 위해 복잡한 레이아웃 CSS를 짤 필요가 거의 없다는 것을 뜻합니다. HTML 소스 순서만 잘 짜두면 모바일에서는 기본적으로 훌륭하게 읽히는 레이아웃이 저절로 완성되기 때문입니다.
💡 강사의 실무 팁! (Mobile-first가 짱인 이유!)
만약 PC 화면을 먼저 꽉 차게 짜두면, 모바일용 미디어 쿼리에서 PC용으로 줬던float,flex, 픽셀 고정값 같은 복잡한 CSS를 일일이 '취소(초기화)'하는 코드를 지저분하게 덕지덕지 써야 합니다. 반대로 모바일(기본)부터 짜면? 스마트폰에서는 가장 가볍고 심플한 CSS만 다운받아 빠르게 렌더링하고, 화면이 넓은 PC에서만 살을 덧붙이는 효율적인 구조가 됩니다. 무조건min-width를 쓰는 버릇을 들이세요!
자, 이제 여러분 차례입니다! 이 튜토리얼 섹션에서 여러분만의 기본적인 모바일 우선 반응형 디자인을 단계별로 구축해 볼 것입니다. 실무 사이트에서는 미디어 쿼리 안에서 조정해야 할 것들이 훨씬 더 많겠지만, 접근 방식 자체는 이것과 100% 동일합니다.
출발점은 기본적인 HTML 문서입니다. 다양한 레이아웃 영역이 눈에 잘 띄도록 박스 배경색만 미리 CSS로 발라두었습니다.
먼저, 아래의 HTML 코드를 복사해서 텍스트 편집기에 붙여 넣고, index.html 같은 이름으로 컴퓨터에 저장한 뒤 브라우저에서 열어보세요.
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Media Queries: a simple mobile first design, step 1</title>
<style>
/* 여기에 스타일을 추가할 겁니다! */
</style>
</head>
<div class="wrapper">
<header>
<nav>
<ul>
<li><a href="">About</a></li>
<li><a href="">Contact</a></li>
<li><a href="">Meet the team</a></li>
<li><a href="">Blog</a></li>
</ul>
</nav>
</header>
<main>
<article>
<div class="content">
<h1>Veggies!</h1>
<p>
Veggies es bonus vobis, proinde vos postulo essum magis kohlrabi welsh
onion daikon amaranth tatsoi tomatillo melon azuki bean garlic.
</p>
</div>
<aside class="related">
<p>
All these veggies are brought to you by the
<a href="[https://veggieipsum.com/](https://veggieipsum.com/)">Veggie Ipsum generator</a>.
</p>
</aside>
</article>
<aside class="sidebar">
<h2>External vegetable-based links</h2>
<ul>
<li><a href="#">How to cook broccoli</a></li>
<li><a href="#">Swiss Chard</a></li>
</ul>
</aside>
</main>
<footer>
<p>© 2024</p>
</footer>
</div>
HTML 소스의 순서를 보세요. 콘텐츠가 논리적으로 잘 읽히도록 위에서 아래로 정렬되어 있습니다. 화면을 읽어주는 스크린 리더기도 이 순서대로 읽게 되므로 매우 중요한 첫 단계입니다.
자, 이제 이 초기 스타일 코드를 방금 저장한 HTML 파일의 <style></style> 태그 안쪽에 붙여 넣어 주세요. /* Add styles here */ 부분을 대체하면 됩니다.
* {
box-sizing: border-box; /* 박스 크기 계산을 편하게 해주는 필수 코드! */
}
body {
width: 90%;
margin: 2em auto;
font: 1em/1.3 "Helvetica", "Arial", sans-serif;
}
a:link,
a:visited {
color: #333333;
}
nav ul,
aside ul {
list-style: none;
padding: 0;
}
/* 메뉴 버튼 스타일링 */
nav a:link,
nav a:visited {
background-color: rgb(207 232 220 / 20%);
border: 2px solid rgb(79 185 227);
text-decoration: none;
display: block; /* a 태그를 블록으로 만들어 위아래로 꽉 차게 쌓이게 합니다 */
padding: 10px;
color: #333333;
font-weight: bold;
}
nav a:hover {
background-color: rgb(207 232 220 / 70%);
}
.related {
background-color: rgb(79 185 227 / 30%);
border: 1px solid rgb(79 185 227);
padding: 10px;
}
.sidebar {
background-color: rgb(207 232 220 / 50%);
padding: 10px;
}
article {
margin-bottom: 1em;
}
개발자 도구의 반응형 디자인 모드를 켜서 보시거나 브라우저 창을 모바일 크기처럼 아주 좁게 줄여보세요. 복잡한 레이아웃 속성을 전혀 쓰지 않았는데도 불구하고, 그냥 위에서 아래로 쭉 떨어지는 형태 자체가 아주 직관적이고 훌륭한 모바일 뷰(mobile view)로 기능하고 있는 것을 보실 수 있습니다! 이것이 바로 모바일-퍼스트의 힘입니다.
이제 브라우저 창을 천천히 옆으로 넓혀보세요. 어느 순간부터 한 줄에 들어가는 글자 수가 너무 많아져서 글을 읽기 힘들어지는 지점이 올 것입니다. 아하! 바로 여기가 네비게이션 메뉴를 가로로 배치하거나 레이아웃을 쪼갤 수 있는 공간이 충분해진 타이밍, 즉 브레이크포인트입니다!
우리는 브레이크포인트 단위로 px 대신 em을 사용할 것입니다. (px 대신 em을 사용하면, 시력이 안 좋아서 폰트 크기를 강제로 크게 키워놓은 사용자에게도 글자가 깨지지 않고 적절한 시점에 반응형 레이아웃이 동작하도록 만들 수 있거든요.)
CSS의 맨 밑에 다음 미디어 쿼리를 추가하세요:
/* 화면 너비가 40em (대략 640px) 이상일 때부터 아래 코드를 덮어써라! */
@media screen and (width >= 40em) {
article {
display: grid;
grid-template-columns: 3fr 1fr; /* 본문을 3:1 비율로 2단 분리! */
column-gap: 20px;
}
nav ul {
display: flex; /* 세로로 쌓여있던 메뉴를 플렉스박스로 가로 배치! */
}
nav li {
flex: 1; /* 메뉴 버튼들이 1:1 비율로 공평하게 공간을 나눠 갖게 함 */
}
}
이 CSS가 적용되면, 태블릿 크기 이상 화면에서는 <article> 안의 본문 내용과 .related 박스가 3:1 비율의 2단(two-column) 레이아웃으로 예쁘게 나뉘게 됩니다. 또한 Flexbox를 사용해서 햄버거 메뉴처럼 세로로 겹쳐있던 네비게이션 버튼들을 시원하게 한 줄(row)로 가로 배치했습니다.
창을 조금 더 넓혀봅시다. 이제 사이드바(.sidebar)까지 끌어올려서 전체를 3단(three-column) 컬럼으로 만들어도 될 만큼 공간이 넉넉해졌네요.
새로운 미디어 쿼리를 작성해서 <main> 요소 전체를 2단 그리드로 만들어 보겠습니다. 그리고 레이아웃을 합치면서 사이드바들의 아래쪽 라인을 맞추기 위해 <article>의 불필요한 margin-bottom을 없애고 푸터에 선을 하나 추가하는 소소한 디자인 수정(tweaks)도 곁들여 주겠습니다. (각 화면 크기별로 이런 소소한 밸런스 패치를 해주는 것이 프론트엔드 개발자의 센스입니다!)
CSS 파일 맨 밑에 아래 코드를 한 번 더 추가해 보세요:
/* 화면 너비가 70em (대략 1120px) 이상일 때부터 아래 코드를 덮어써라! */
@media screen and (width >= 70em) {
main {
display: grid;
grid-template-columns: 3fr 1fr; /* 본문 전체 덩어리와 사이드바를 3:1로 분리! */
column-gap: 20px;
}
article {
margin-bottom: 0; /* 레이아웃 정렬을 위한 마진 제거 */
}
footer {
border-top: 1px solid #cccccc;
margin-top: 2em; /* 푸터에 구분선 추가 */
}
}
이제 모든 작업이 끝났습니다! 창 너비를 줄였다 늘였다 해보시면, 화면 너비에 따라 디자인이 1단(모바일), 2단(태블릿), 3단(데스크톱)으로 물 흐르듯 변신(respond)하는 것을 볼 수 있습니다. 이것이 바로 모바일 우선(mobile-first) 방식의 반응형 디자인이 작동하는 기초 원리입니다!
위 예제의 HTML 소스 코드의 <head> 부분을 살펴보시면, 아까 이런 코드가 들어있던 것을 기억하실 겁니다:
<meta name="viewport" content="width=device-width,initial-scale=1" />
이것은 viewport 메타 태그입니다. 이 한 줄은 모바일 브라우저가 반응형 미디어 쿼리를 제대로 인식하고 렌더링하게 만드는 가장 중요하고 절대적인 마법의 주문입니다!
스마트폰 브라우저들은 아주 똑똑하고(?) 고집이 셉니다. 만약 이 태그가 없으면, 스마트폰 브라우저는 스스로 "아, 이 사이트는 옛날 PC용 사이트인가 보군. 모바일 화면(320px)으로 좁게 보여주면 레이아웃이 다 박살 날 테니까, 억지로 가로 980px 짜리 거대한 가상 화면에 사이트를 그린 다음 엄청 쪼그맣게 축소해서 폰 화면에 우겨넣어 보여줘야지!"라고 멋대로 판단해 버립니다. 이렇게 되면 우리가 기껏 짜놓은 max-width: 600px 같은 모바일용 미디어 쿼리가 절대 발동하지 않게 됩니다! (브라우저가 자기 너비를 980px이라고 속이고 있으니까요.)
하지만 저 메타 태그를 넣어주면 브라우저에게 이렇게 명령하는 셈이 됩니다. "내 사이트 너비를 억지로 980px로 뻥튀기하지 마! 그냥 네 실제 핸드폰 기기의 너비(device-width)를 100% 비율(initial-scale=1)로 정직하게 화면에 띄워!"
그제야 비로소 스마트폰 브라우저는 자신의 진짜 너비(예: 390px)를 인식하게 되고, 우리가 만들어둔 모바일용 미디어 쿼리가 정상적으로 발동하게 되는 것입니다.
이것이 왜 필요한지에 대한 더 자세한 이야기는 이전 글의 viewport 메타 태그 섹션을 다시 확인해 보세요.
Flexbox와 CSS Grid라는 최신 기술은 미디어 쿼리를 단 한 줄도 쓰지 않고도 기가 막힌 반응형 컴포넌트를 만들 수 있는 강력한 기능들을 제공합니다. 그래서 무조건 뷰포트 크기에 맞춰서 @media를 난사하기 전에, "혹시 이거 CSS Grid만으로 알아서 늘어났다 줄어들게 만들 수 있지 않을까?"를 항상 고민해 보는 것이 좋습니다.
예를 들어, 쇼핑몰에 상품 카드들이 쫙 깔려있다고 쳐봅시다. 우리는 이 카드들이 "최소 200px" 너비는 유지했으면 좋겠고, 화면이 넓어지면 그 빈 공간에 맞춰서 한 줄에 들어가는 카드 개수를 최대한 꽉꽉 채워 넣고 싶습니다.
놀랍게도, 이 동작은 미디어 쿼리 없이 CSS Grid 단 3줄로 완벽하게 구현할 수 있습니다!
<ul class="grid">
<li><h2>Card 1</h2><p>…</p></li>
<li><h2>Card 2</h2><p>…</p></li>
<li><h2>Card 3</h2><p>…</p></li>
<li><h2>Card 4</h2><p>…</p></li>
<li><h2>Card 5</h2><p>…</p></li>
</ul>
body {
font: 1.2em / 1.5 sans-serif;
}
.grid {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 20px;
/* 아래 한 줄이 바로 미디어 쿼리 킬러입니다! */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.grid li {
border: 1px solid #666666;
padding: 10px;
}
위 코드를 적용하고 브라우저 창 너비를 늘렸다 줄였다 해보세요. auto-fill과 minmax(200px, 1fr)의 조합 덕분에 화면 공간이 허락하는 한 카드가 한 줄에 5개, 4개, 2개, 1개로 알아서 줄바꿈 되며 쫀득하게(flexible) 재배열되는 것을 볼 수 있습니다.
이 방법이 미디어 쿼리보다 우월한 점은, 이 그리드 시스템이 '화면(뷰포트) 전체의 너비'를 보는 게 아니라 '이 컴포넌트(ul)가 놓여있는 실제 가용 공간의 너비'를 기준으로 작동한다는 점입니다. (사이드바 옆에 있든, 좁은 팝업창 안에 있든 알아서 부모 공간에 맞춰 반응합니다!)
미디어 쿼리에 대한 섹션을 마무리하면서 "사실 미디어 쿼리 안 써도 돼!"라고 제안하는 게 좀 이상해 보일 수도 있겠습니다. 하지만 실무에서는 CSS Grid나 Flexbox 같은 최신 레이아웃 기법이 제공하는 이 강력한 반응형 기능들을 기본 뼈대로 쓰고, 그것만으로 커버가 안 되는 큼직한 덩어리의 레이아웃 변경에만 미디어 쿼리를 스파이스(양념)처럼 더해서(enhanced) 사용하는 것이 가장 완벽한 최고의 결과물을 만들어내는 비결입니다!
이 레슨을 통해 여러분은 미디어 쿼리가 무엇인지 배웠고, 모바일 우선(mobile-first) 방식의 반응형 디자인을 실무에서 어떻게 구축하는지 직접 튜토리얼을 통해 실습해 보았습니다.
우리가 만든 코드를 출발점 삼아 더 다양한 미디어 쿼리를 테스트해 보세요. 예를 들어, pointer: coarse 미디어 특성을 사용해서 "사용자가 뭉툭한 손가락으로 화면을 터치하는 기기일 경우에만 모바일 네비게이션 버튼 크기를 훨씬 더 큼직하게 뚱뚱하게 만들어줘!"라는 센스 있는 코드를 추가해 볼 수도 있을 것입니다.
또한, 어떤 컴포넌트를 반응형으로 만들 때 미디어 쿼리를 쓰는 게 나을지, 아니면 플렉스박스나 그리드 같은 최신 레이아웃 메서드에 내장된 자동 반응형 기능을 쓰는 게 나을지 이리저리 실험해 보세요. 웹 개발에 정답이나 오답은 없습니다. — 여러분의 디자인과 콘텐츠에 어떤 방식이 가장 우아하게 작동하는지 직접 부딪혀보며 찾아내는 것이 중요합니다.
자, 이제 이 길고 험난했던 레이아웃 모듈의 끝이 보입니다! 다음 글에서는 지금까지 배운 반응형 웹 디자인과 미디어 쿼리에 대한 지식들을 머릿속에 꽉꽉 채워 넣었는지 확인해 볼 수 있는 재미있는 테스트들을 제공해 드릴게요.
이전 페이지 (Overview: CSS layout) | 개요: CSS 레이아웃 | 다음 페이지 (Test your skills: Responsive design)