반응형 웹 디자인 기초
viewport와 미디어 쿼리, 유동 크기와 반응형 이미지를 적용해 모바일부터 데스크톱까지 레이아웃을 조정합니다.
지금까지 우리는 HTML로 웹 페이지 구조를 만들고, CSS로 색상·폰트·텍스트 스타일을 적용하며, Flexbox와 Grid로 다양한 레이아웃을 구현하는 방법을 학습했습니다.
그런데 현재 웹에 접속하는 사용자들은 데스크톱, 노트북뿐 아니라 스마트폰, 태블릿처럼 화면 크기가 매우 다양한 디바이스를 사용합니다.
단순히 하나의 레이아웃만으로 모든 디바이스에서 최적의 사용자 경험을 제공하기는 어렵습니다.
여기서 등장하는 개념이 바로 반응형 웹 디자인(Responsive Web Design, RWD)입니다.
반응형 웹 디자인은 기기 화면 크기에 따라 레이아웃과 디자인을 자동으로 조정해, 어떤 환경에서도 최적화된 형태로 콘텐츠를 보여주는 설계 방식입니다.
이는 사용성(Usability)과 접근성(Accessibility)을 크게 향상시키며, 모든 사용자에게 일관되고 긍정적인 경험을 제공하는 데 필수적입니다.
이 장에서는 반응형 웹 디자인의 핵심 개념과, 이를 구현하는 기본 기술인 미디어 쿼리(Media Query)를 중심으로 정리합니다.
학습 후에는 다양한 디바이스에서 안정적으로 동작하는 레이아웃을 스스로 설계할 수 있습니다.
RESPONSIVE REFLOW
같은 내용을 1열에서 2열·3열로 재배치합니다
모바일 기본 배치를 먼저 작성하고, 실습의 min-width 조건에서 Grid 영역과 내비게이션 방향을 바꿉니다.
기본 · 1열
header → nav → main → aside → footer. nav의 링크는 가로로 배치하고 공간이 부족하면 줄바꿈합니다.
768px 이상 · 2열
nav는 위에, main과 aside는 나란히 배치합니다.
1024px 이상 · 3열
nav가 왼쪽 열로 이동하고 링크를 세로로 배치합니다.
열 수를 바꿔도 읽기·focus 순서는 HTML에서 시작합니다
본문 폭, 이미지 max-width: 100%·height: auto, 자연스러운 줄바꿈을 먼저 설정합니다. 콘텐츠가 겹치거나 읽기 힘들어지는 지점에서 레이아웃을 조정합니다.
768px·1024px는 이 실습의 기준이며 모든 사이트의 정답이 아닙니다. 각 폭에서 터치 영역, 확대, 콘텐츠 손실, reduced motion과 색 대비를 확인합니다. 그림의 박스 폭은 구조를 위한 도식입니다.
반응형 웹 디자인이란?
반응형 웹 디자인은 웹 페이지가 사용자의 화면 크기(Viewport), 해상도, 장치 방향(가로/세로) 등 다양한 조건에 반응하여 자신을 최적화하는 디자인 방식입니다.
같은 HTML의 내용을 뷰포트와 사용자 조건에 맞추어 재배치하는 방식입니다. 하나의 CSS 파일이어야 하는 것은 아니며, 이 실습은 한 파일에 기본 규칙과 화면 너비별 규칙을 모아 비교합니다.
반응형 웹 디자인의 주요 구성 요소플렉서블 그리드 (Flexible Grid Layout): px과 같은 고정 단위 대신 %, em, rem, vw, vh, fr과 같은 상대적인 단위를 사용하여 레이아웃 요소의 크기를 유연하게 조절합니다.
(Flexbox와 Grid가 핵심 도구)
플렉서블 이미지 및 미디어 (Flexible Images and Media): 이미지나 비디오 등의 미디어 요소가 컨테이너 크기에 맞춰 자동으로 조절되도록 합니다.
(max-width: 100%; height: auto;가 대표적)
미디어 쿼리 (Media Queries): 특정 조건(예: 화면 너비)에 따라 다른 CSS 스타일을 적용할 수 있도록 해주는 CSS3 기능입니다.
이 장의 핵심 내용입니다.
뷰포트 메타 태그
반응형 웹 디자인을 시작하기 전에 HTML 문서의 <head> 태그 안에 반드시 추가해야 하는 메타 태그입니다.
이 태그는 모바일 브라우저의 레이아웃 뷰포트를 장치의 CSS 픽셀 너비에 맞추고 초기 확대 비율을 정합니다. CSS 픽셀은 화면의 물리 픽셀과 1:1로 같다는 뜻이 아닙니다. DPR과 확대가 서로 다른 기준이므로 고해상도 화면이라고 미디어 쿼리의 너비가 곧 물리 픽셀 수가 되지는 않습니다. viewport 설정을 참고하세요.
이 태그가 없으면 모바일 브라우저는 데스크톱 페이지를 축소하여 보여주려 합니다.
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>반응형 웹 페이지</title>
<link rel="stylesheet" href="css/style.css">
</head>width=device-width: 웹 페이지의 너비를 장치 화면의 너비에 맞춥니다.initial-scale=1.0: 페이지가 처음 로드될 때 초기 확대/축소 수준을 1배(원본 크기)로 설정합니다.
앞의 반응형 reflow 다이어그램은 소스 순서에서 시작해 유동 크기, 콘텐츠 임계점, 열 재배치, 사용성 검증으로 이어지는 순서를 보여줍니다.
미디어 쿼리 (Media Queries)
미디어 쿼리는 특정 미디어 유형(스크린, 프린트 등)이나 미디어 기능(화면 너비, 높이, 장치 방향 등)에 따라 CSS 스타일을 조건부로 적용할 수 있게 해주는 강력한 기능입니다.
미디어 쿼리 기본 문법
미디어 쿼리는 @media 규칙을 사용합니다.
@media media-type and (media-feature) {
/* 여기에 특정 조건이 충족될 때 적용될 CSS 규칙 작성 */
}-
media-type(미디어 유형)all(기본값): 모든 미디어 장치screen: 컴퓨터 화면, 태블릿, 스마트폰 등 컬러 스크린 장치print: 프린터- 현재 사용하는 미디어 유형은
all,screen,print입니다. 과거의speech같은 유형을 스크린 리더 접근성의 분기 조건으로 사용하지 않습니다. 접근 가능한 HTML과 읽기 순서는 기본 문서에서 보장하고, 필요하면 현재 미디어 기능을 선택합니다.
-
media-feature(미디어 기능)- 가장 흔하게 사용되는 것은
width(너비)와 관련된 기능입니다. width: 뷰포트 너비height: 뷰포트 높이min-width: 최소 뷰포트 너비 (해당 너비 이상일 때 적용)max-width: 최대 뷰포트 너비 (해당 너비 이하일 때 적용)orientation: 장치 방향 (portrait(세로),landscape(가로))resolution: 장치 해상도prefers-color-scheme: 사용자의 다크/라이트 모드 선호도 (light,dark)- 그 외 다양한 기능들이 있습니다.
- 가장 흔하게 사용되는 것은
가장 일반적인 미디어 쿼리 사용 예시
화면 너비에 따라 레이아웃을 변경하는 것이 가장 흔한 시나리오입니다.
/* 기본 스타일 (모바일 우선, Mobile First) */
body {
background-color: lightblue;
color: #333;
font-size: 16px;
}
.container {
width: 95%;
margin: 0 auto;
padding: 10px;
background-color: white;
}
/* 스크린 너비가 600px 이상일 때 적용되는 스타일 (태블릿) */
@media screen and (min-width: 600px) {
body {
background-color: lightgreen;
font-size: 17px;
}
.container {
width: 80%;
padding: 20px;
}
}
/* 스크린 너비가 1024px 이상일 때 적용되는 스타일 (데스크톱) */
@media screen and (min-width: 1024px) {
body {
background-color: lightcoral;
font-size: 18px;
}
.container {
width: 70%;
max-width: 1000px;
padding: 30px;
}
}💡 Mobile First (모바일 우선) 접근 방식:
위 예시처럼 가장 작은 화면(모바일)에 최적화된 기본 스타일을 먼저 작성하고, min-width 미디어 쿼리를 사용하여 점진적으로 더 큰 화면(태블릿, 데스크톱)에 대한 스타일을 추가하는 방식입니다.
이 방식은 성능 최적화와 코드 관리에 유리하여 현대 웹 개발에서 널리 사용됩니다.
💡 Desktop First (데스크톱 우선) 접근 방식:
반대로 가장 큰 화면(데스크톱)에 최적화된 기본 스타일을 먼저 작성하고, max-width 미디어 쿼리를 사용하여 점진적으로 더 작은 화면(태블릿, 모바일)에 대한 스타일을 추가하는 방식입니다.
/* 기본 스타일 (데스크톱 우선, Desktop First) */
body {
background-color: lightcoral;
font-size: 18px;
}
.container {
width: 70%;
max-width: 1000px;
margin: 0 auto;
padding: 30px;
background-color: white;
}
/* 스크린 너비가 1023px 이하일 때 적용되는 스타일 (태블릿) */
@media screen and (max-width: 1023px) {
body {
background-color: lightgreen;
font-size: 17px;
}
.container {
width: 80%;
padding: 20px;
}
}
/* 스크린 너비가 599px 이하일 때 적용되는 스타일 (모바일) */
@media screen and (max-width: 599px) {
body {
background-color: lightblue;
font-size: 16px;
}
.container {
width: 95%;
padding: 10px;
}
}두 방식 모두 사용할 수 있습니다. 이 실습은 좁은 화면에서 콘텐츠를 잃지 않는 기본 배치를 먼저 만들고, 공간이 충분할 때 열을 늘리는 Mobile First를 사용합니다. 선택의 이유를 트래픽의 일반 추세보다 현재 콘텐츠와 구현 조건에 연결하세요.
여러 조건 결합하기
and, , (쉼표, OR), not 키워드를 사용하여 여러 조건을 결합할 수 있습니다.
and(AND): 모든 조건이 참일 때 적용됩니다.@media screen and (min-width: 768px) and (max-width: 1024px) { /* 화면 너비가 768px 이상 1024px 이하일 때 */ } @media (min-height: 400px) and (orientation: landscape) { /* 높이가 400px 이상이고 가로 모드일 때 */ },(쉼표, OR): 나열된 조건 중 하나라도 참일 때 적용됩니다.@media screen and (max-width: 600px), print { /* 화면 너비가 600px 이하이거나 인쇄할 때 */ }not(NOT): 조건을 반전시킵니다.@media not screen and (orientation: landscape) { /* 스크린 장치이면서 가로 모드인 조건 전체를 제외 */ }
반응형 이미지를 위한 CSS
이미지는 웹 페이지의 용량을 크게 차지하고 레이아웃을 망가뜨릴 수 있으므로, 반응형 디자인에서 특별히 신경 써야 합니다.
max-width: 100%;: 이미지가 부모 요소의 너비를 넘지 않도록 합니다. 부모 요소의 크기가 줄어들면 이미지도 함께 줄어들어 넘치지 않습니다.height: auto;: 이미지의 너비가 조절될 때, 높이는 비율에 맞춰 자동으로 조절되도록 합니다. 이를 통해 이미지 비율이 깨지는 것을 방지합니다.
img {
max-width: 100%;
height: auto; /* 이미지의 원본 비율 유지 */
display: block; /* 가끔 인라인 요소로 인한 하단 여백 제거 */
}실습: 미디어 쿼리를 이용한 반응형 블로그
이전 Flexbox와 Grid 실습에서 만들었던 레이아웃에 미디어 쿼리를 적용하여 다양한 화면 크기에 대응하는 반응형 블로그 레이아웃을 만들어 봅시다.
responsive_blog.html 파일 작성<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>반응형 블로그 레이아웃</title>
<link rel="stylesheet" href="css/responsive.css">
</head>
<body>
<div class="page-wrapper">
<header class="header">
<h1>반응형 블로그</h1>
<p>모든 화면에서 읽기 쉬운 레이아웃</p>
</header>
<nav class="main-nav">
<ul>
<li><a href="#">홈</a></li>
<li><a href="#">카테고리</a></li>
<li><a href="#">연락처</a></li>
<li><a href="#">로그인</a></li>
</ul>
</nav>
<main class="main-content">
<article class="blog-post">
<h2>반응형 웹 디자인이란?</h2>
<p>반응형 웹 디자인은 하나의 웹사이트가 다양한 기기(데스크톱, 태블릿, 스마트폰)에서 최적의 형태로 보여지도록 설계하는 기법입니다. 이는 사용자 경험을 향상시키고, 개발 및 유지보수 비용을 절감하는 효과가 있습니다.</p>
<p>핵심 기술로는 유동적인 그리드 레이아웃, 유동적인 이미지 및 미디어, 그리고 미디어 쿼리가 있습니다. 특히 미디어 쿼리는 특정 화면 크기나 장치 특성에 따라 다른 CSS 스타일을 적용할 수 있게 해주는 핵심 도구입니다.</p>
<h3>미디어 쿼리 활용법</h3>
<p>미디어 쿼리는 `@media` 규칙을 사용하여 정의하며, `min-width`, `max-width`, `orientation` 등 다양한 미디어 기능을 조건으로 활용할 수 있습니다. 예를 들어, 모바일 화면에서는 내비게이션 메뉴를 숨기거나, 텍스트 크기를 조절하는 등의 변화를 줄 수 있습니다.</p>
</article>
<div class="related-posts">
<h3>최신 글</h3>
<ul>
<li><a href="#">Flexbox 완전 정복</a></li>
<li><a href="#">CSS Grid 심화 학습</a></li>
<li><a href="#">웹 접근성의 중요성</a></li>
</ul>
</div>
</main>
<aside class="sidebar">
<h3>공지사항</h3>
<p>이번 달 웹 개발 스터디는 매주 화요일 저녁 7시입니다.</p>
<h3>인기 태그</h3>
<div class="tags">
<span>#CSS</span>
<span>#HTML</span>
<span>#JavaScript</span>
<span>#WebDev</span>
<span>#Frontend</span>
</div>
</aside>
<footer class="footer">
<p>© 2025 반응형 블로그. 모든 권리 보유.</p>
</footer>
</div>
</body>
</html>css/responsive.css 파일 작성/* 뷰포트 메타 태그가 HTML에 설정되어 있는지 확인! */
/* 전역 스타일 및 초기 설정 (Mobile First) */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f0f2f5;
color: #333;
line-height: 1.6;
}
.page-wrapper {
display: grid; /* Grid 컨테이너 */
gap: 15px; /* 기본 간격 */
grid-template-columns: 1fr; /* 모바일: 모든 영역 한 줄로 */
grid-template-areas:
"header"
"main-nav"
"main-content"
"sidebar"
"footer";
max-width: 100%;
margin: 0 auto;
padding: 10px; /* 기본 패딩 */
}
/* 공통 스타일 */
.page-wrapper > * {
background-color: white;
padding: 15px; /* 기본 패딩 */
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
/* 헤더 */
.header {
grid-area: header;
background-color: #2c3e50;
color: white;
text-align: center;
padding: 20px 15px;
}
.header h1 { font-size: 2em; margin-bottom: 5px; }
.header p { font-size: 0.9em; }
/* 내비게이션 */
.main-nav {
grid-area: main-nav;
background-color: #34495e;
color: white;
}
.main-nav ul {
list-style: none;
display: flex; /* 메뉴 아이템들을 Flexbox로 가로 정렬 */
flex-wrap: wrap; /* 공간 부족 시 줄바꿈 */
justify-content: center; /* 가운데 정렬 */
gap: 10px;
}
.main-nav li { margin: 0; }
.main-nav a {
display: block;
color: white;
text-decoration: none;
padding: 8px 12px;
border-radius: 5px;
transition: background-color 0.3s ease;
}
.main-nav a:hover {
background-color: #4a6581;
}
/* 메인 콘텐츠 */
.main-content {
grid-area: main-content;
}
.main-content h2 {
color: #2980b9;
margin-bottom: 10px;
font-size: 1.6em;
}
.main-content h3 {
color: #4a6581;
margin-top: 20px;
margin-bottom: 8px;
font-size: 1.2em;
}
.main-content p {
margin-bottom: 1em;
}
.blog-post img {
max-width: 100%; /* 반응형 이미지 */
height: auto;
display: block;
margin: 0 auto 15px auto;
border-radius: 5px;
}
.related-posts ul {
list-style: none;
margin-top: 10px;
}
.related-posts li a {
display: block;
padding: 8px 0;
border-bottom: 1px dotted #ccc;
color: #333;
text-decoration: none;
}
.related-posts li:last-child a { border-bottom: none; }
.related-posts li a:hover { color: #2980b9; }
/* 사이드바 */
.sidebar {
grid-area: sidebar;
background-color: #ecf0f1;
}
.sidebar h3 {
color: #2c3e50;
margin-bottom: 10px;
font-size: 1.2em;
}
.tags span {
display: inline-block;
background-color: #bdc3c7;
color: white;
padding: 5px 10px;
border-radius: 15px;
font-size: 0.8em;
margin: 5px 5px 0 0;
}
/* 푸터 */
.footer {
grid-area: footer;
background-color: #34495e;
color: white;
text-align: center;
padding: 15px;
font-size: 0.8em;
}
/* ----------------------------------------------------- */
/* 미디어 쿼리 시작 (태블릿 크기, min-width: 768px) */
/* ----------------------------------------------------- */
@media screen and (min-width: 768px) {
.page-wrapper {
grid-template-columns: 1fr 250px; /* 메인 1fr, 사이드바 250px */
grid-template-areas:
"header header"
"main-nav main-nav"
"main-content sidebar" /* 메인 콘텐츠와 사이드바가 나란히 */
"footer footer";
gap: 20px; /* 간격 늘림 */
padding: 20px; /* 패딩 늘림 */
}
.header h1 { font-size: 2.5em; }
.header p { font-size: 1em; }
.main-nav ul {
justify-content: flex-start; /* 왼쪽 정렬 */
gap: 20px;
}
.main-nav a { padding: 10px 15px; }
.main-content h2 { font-size: 2em; }
.main-content h3 { font-size: 1.5em; }
.sidebar h3 { font-size: 1.5em; }
.tags span { font-size: 0.9em; }
.footer { font-size: 0.9em; }
}
/* ----------------------------------------------------- */
/* 미디어 쿼리 시작 (데스크톱 크기, min-width: 1024px) */
/* ----------------------------------------------------- */
@media screen and (min-width: 1024px) {
.page-wrapper {
grid-template-columns: 200px 1fr 280px; /* 네비게이션 200px, 메인 가변, 사이드바 280px */
grid-template-areas:
"header header header"
"main-nav main-content sidebar" /* 네비게이션, 메인, 사이드바 나란히 */
"footer footer footer";
max-width: 1400px; /* 최대 너비 더 넓게 */
padding: 30px;
gap: 30px;
}
/* 네비게이션은 세로로 */
.main-nav {
padding: 20px;
}
.main-nav ul {
flex-direction: column; /* 세로 정렬 */
align-items: flex-start; /* 왼쪽 정렬 */
gap: 15px;
}
.main-nav a {
width: 100%; /* 너비 전체 차지 */
text-align: left;
padding: 12px 15px;
font-size: 1.1em;
}
.header h1 { font-size: 3em; }
.header p { font-size: 1.1em; }
.main-content h2 { font-size: 2.5em; }
.main-content h3 { font-size: 1.8em; }
.main-content p { font-size: 1.1em; }
.sidebar h3 { font-size: 1.8em; }
.tags span { font-size: 1em; }
.footer { font-size: 1em; }
}- Live Server를 통해
responsive_blog.html파일을 열어 보세요. - 브라우저 창의 너비를 조절해 보세요.
- 가장 좁은 너비 (모바일): 모든 섹션(헤더, 내비게이션, 메인, 사이드바, 푸터)이 세로로 쌓여 있을 것입니다. 내비게이션 링크는 가로로 배치되고, 공간이 부족하면 다음 줄로 넘어갑니다.
- 중간 너비 (태블릿, 약 768px 이상): 메인 콘텐츠와 사이드바가 가로로 나란히 배치되는 2열 레이아웃으로 변경될 것입니다. 내비게이션은 여전히 상단에 가로로 배치됩니다.
- 넓은 너비 (데스크톱, 약 1024px 이상): 내비게이션이 메인 콘텐츠 왼쪽에 세로로 배치되고, 메인 콘텐츠와 사이드바가 오른쪽에 나란히 있는 3열 레이아웃으로 변경될 것입니다.
- 이 HTML에는 이미지가 없으므로 이미지 크기 변화는 관찰하지 않습니다.
.blog-post img규칙은 나중에 이미지를 추가했을 때 적용됩니다. - 이 실습을 통해 미디어 쿼리가 웹 페이지의 레이아웃과 스타일을 다양한 디바이스에 맞게 동적으로 변경하는 강력한 도구임을 직접 경험할 수 있습니다.
이번 장에서는 현대 웹 개발의 필수적인 요소인 반응형 웹 디자인(Responsive Web Design)의 기초를 학습했습니다.
웹 페이지가 다양한 화면 크기에 맞춰 최적의 사용자 경험을 제공하도록 설계하는 것의 중요성을 이해하고, 이를 구현하는 핵심 기술인 미디어 쿼리(Media Query)의 기본 문법과 활용법을 익혔습니다.
특히 모바일 우선(Mobile First) 접근 방식의 장점을 강조하고, 반응형 이미지를 처리하는 방법도 다루었습니다.
HTML 구조, CSS 스타일, Flexbox/Grid 레이아웃, 미디어 쿼리를 함께 사용하면 화면 크기에 따라 조정되는 반응형 웹 페이지를 만들 수 있습니다.
반응형 웹 디자인은 모바일 우선 흐름을 기준으로 확장하고 터치, 확대, 콘텐츠 손실을 함께 점검합니다.
경계 폭에서 적용 규칙 예측하기
현재 responsive.css를 변경하지 않고 767px·768px·1023px·1024px에서 적용되는 미디어 쿼리와 열 수를 먼저 표로 적으세요. 1024px에서 “768px 규칙이 꺼졌다”라고 설명해도 될까요?
조건과 cascade 확인
767px은 기본 한 열, 768px부터 1023px까지는 768px 쿼리의 두 열입니다. 1024px에서는 두 min-width 쿼리가 모두 참입니다. 같은 specificity의 같은 속성에 뒤쪽 1024px 선언이 적용되어 세 열이 됩니다. 768px 규칙의 속성 중 뒤에서 다시 지정하지 않은 것은 계속 적용됩니다.
독립 변경과 관찰
사이드바가 두 열에서 너무 좁다고 가정하고 768px 쿼리의 열 선언을 1fr 300px로 바꾸세요. 화면 800px에서는 어느 열이 늘고 어느 열이 줄까요? 기본 한 열인 375px 화면은 왜 그대로일까요? 글자가 넘치거나 꼭 필요한 내용이 숨지 않았는지도 대조하세요.
현재 태그 배지의 흰 글자와 #bdc3c7 배경은 일반 글자의 대비 기준에 부족합니다(약 1.78:1). .tags span의 글자색을 #25303b처럼 어두운 값으로 바꾸고 배경과 함께 확인하세요. 반응형은 열이 맞는 것 외에도 글자가 읽히고 키보드·확대에서도 내용이 이어져야 합니다.