CSS / 반응형 레이아웃 만들기
반응형 레이아웃은 브라우저의 표시 영역에 맞춰 콘텐츠의 너비와 열 배치를 바꾸는 방식입니다. 작은 화면에서는 한 열로 읽기 쉽게 배치하고, 공간이 충분해지면 @media 조건으로 본문과 사이드바를 나란히 놓을 수 있습니다. 기기의 이름이나 물리적인 화면 해상도보다 실제로 콘텐츠를 표시할 수 있는 뷰포트 너비를 기준으로 설계하는 것이 핵심입니다.
반응형 배치에 필요한 세 가지
반응형 웹디자인에는 화면에 맞춰 줄어드는 바깥 상자, 넘치지 않는 내부 콘텐츠, 필요할 때 배치를 바꾸는 조건이 함께 필요합니다. 미디어 쿼리만 추가하고 본문에 큰 고정 너비가 남아 있으면 좁은 화면에서는 여전히 가로 스크롤이 생깁니다.
- 유동적인 너비: 페이지가 사용 가능한 공간 안에 들어오도록 백분율이나
calc()로 너비를 정하고max-width로 너무 넓어지는 것을 제한합니다. - 콘텐츠의 크기 제한: Grid 항목에는 필요에 따라
min-width: 0을 사용하고, 이미지에는max-width: 100%; height: auto;를 적용합니다. - 레이아웃 전환:
@media (min-width: ...)등의 조건에서 열 개수와 배치를 바꿉니다.
또한 HTML의 <head> 안에 다음 메타 태그를 넣습니다. 모바일 브라우저가 기기의 표시 너비에 맞는 뷰포트를 사용하도록 하는 설정입니다. 확대 기능을 막는 user-scalable=no나 과도한 확대 제한을 추가하지 마세요. MDN의 viewport 메타 태그 설명에서 각 값의 역할을 확인할 수 있습니다.
<meta name="viewport" content="width=device-width, initial-scale=1">
모바일 우선과 데스크톱 우선의 차이
모바일 우선은 좁은 화면에 필요한 기본 스타일부터 작성하고 min-width 조건에서 넓은 화면의 배치를 추가하는 방식입니다. 반대로 데스크톱 우선은 넓은 화면의 기본 배치를 작성하고 max-width 조건에서 작은 화면의 배치를 덮어씁니다. 둘 다 반응형 페이지를 만들 수 있지만, 이 글에서는 기본 한 열 구조가 명확한 모바일 우선을 사용합니다.
미디어 쿼리는 해당 조건에 들어간 스타일만 단독으로 실행하는 기능이 아닙니다. 기본 스타일과 조건을 만족한 규칙들이 함께 CSS의 우선순위에 따라 적용됩니다. 예를 들어 1,100px 화면은 min-width: 768px과 min-width: 1100px 조건을 모두 만족합니다. 같은 선택자와 속성을 사용했다면 뒤에 작성한 1,100px 규칙이 앞의 값을 덮어씁니다.
배치가 바뀌는 기준점을 브레이크포인트(breakpoint)라고 합니다. 예제의 768px과 1,100px은 이 콘텐츠를 배치하기 위한 실습 값이며, 모든 태블릿이나 데스크톱에 적용해야 하는 표준 기기 크기는 아닙니다. 실제 콘텐츠와 번역문 길이, 확대 상태에서 열이 지나치게 좁아지는 지점을 보고 기준을 정합니다.
전체 예제: 한 열에서 두 열·세 열로 바꾸기
다음 코드를 responsive-layout.html로 저장해 브라우저에서 엽니다. HTML 한 파일로 실행되며 외부 라이브러리는 필요하지 않습니다. 브라우저 창을 줄이거나 개발자 도구의 반응형 화면에서 너비를 바꿔 보세요.
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>반응형 레이아웃 실습</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body {
margin: 0;
background: #eef2f6;
color: #243449;
font-family: "Noto Sans KR", sans-serif;
line-height: 1.7;
}
.page {
width: calc(100% - 32px);
max-width: 1100px;
margin: 24px auto;
}
.panel {
min-width: 0;
padding: 20px;
border: 1px solid #b8c6d4;
background: white;
overflow-wrap: anywhere;
}
header.panel, footer.panel { background: #e8f0f9; }
h1, h2 { margin-top: 0; }
img { max-width: 100%; height: auto; }
.layout {
display: grid;
grid-template-columns: minmax(0, 1fr);
grid-template-areas: "menu" "main" "side";
gap: 20px;
margin-block: 20px;
}
.menu { grid-area: menu; }
.content { grid-area: main; }
.sidebar { grid-area: side; background: #fff4d9; }
.menu ul {
display: flex;
flex-wrap: wrap;
gap: 12px;
padding: 0;
margin: 0;
list-style: none;
}
a { color: #174e94; }
@media (min-width: 768px) {
.layout {
grid-template-columns: minmax(0, 1fr) 240px;
grid-template-areas: "menu menu" "main side";
}
}
@media (min-width: 1100px) {
.layout {
grid-template-columns: 160px minmax(0, 1fr) 240px;
grid-template-areas: "menu main side";
}
.menu ul { display: block; }
.menu li + li { margin-top: 12px; }
}
</style>
</head>
<body>
<div class="page">
<header class="panel">
<h1>반응형 레이아웃</h1>
<p>화면 너비를 바꾸며 콘텐츠가 읽기 좋은 배치를 확인합니다.</p>
</header>
<div class="layout">
<nav class="panel menu" aria-label="페이지 목차">
<ul>
<li><a href="#article">본문 보기</a></li>
<li><a href="#notice">안내 보기</a></li>
</ul>
</nav>
<main class="panel content" id="article">
<h2>본문</h2>
<p>좁은 화면에서는 메뉴, 본문, 안내를 위에서 아래로 읽습니다.</p>
<p>너비가 충분해지면 같은 HTML을 유지하면서 열 배치만 바꿉니다.</p>
</main>
<aside class="panel sidebar" id="notice">
<h2>안내</h2>
<p>작은 화면에서도 안내 내용은 사라지지 않고 본문 아래에 놓입니다.</p>
</aside>
</div>
<footer class="panel">창의 너비를 바꿔 배치를 비교해 보세요.</footer>
</div>
</body>
</html>
메뉴, 본문, 안내는 화면이 바뀌어도 같은 내용을 유지합니다. 좁은 화면에서는 차례대로 쌓이고, 중간 너비에서는 메뉴 아래에 본문과 안내가 나란히 놓이며, 넓은 화면에서는 세 영역이 한 행을 이룹니다.
너비별 예상 결과와 확인 방법
| 뷰포트 너비 | 적용되는 배치 | 확인할 점 |
|---|---|---|
| 768px 미만 | 메뉴 → 본문 → 안내의 한 열 | 각 패널이 화면을 넘지 않고 내용이 모두 보이는지 확인합니다. |
| 768px 이상, 1,100px 미만 | 메뉴는 위, 본문과 안내는 두 열 | 오른쪽 안내 열은 240px이며 본문이 남는 너비를 사용합니다. |
| 1,100px 이상 | 메뉴·본문·안내의 세 열 | 왼쪽 160px, 오른쪽 240px, 가운데는 나머지 너비입니다. |
개발자 도구에서 390px, 767px, 768px, 1,099px, 1,100px 순서로 바꿔 보세요. 특히 전환 직전과 직후를 비교해야 겹치거나 비는 범위를 찾기 쉽습니다. 가로 스크롤이 없는지, 문단이 패널 밖으로 나가지 않는지, 메뉴의 두 링크가 각각 본문과 안내로 이동하는지도 확인합니다.
.page의 width: calc(100% - 32px)는 부모의 사용 가능한 너비에서 총 32px을 뺀 값입니다. 가운데 정렬과 결합해 작은 화면에서도 양옆에 기본 여백을 남깁니다. max-width: 1100px는 큰 모니터에서 페이지가 계속 넓어지는 것을 막습니다. 세 열이 되는 기준 1,100px은 뷰포트 조건이고, 페이지가 최대 너비에 도달하는 시점과는 다릅니다.
실습 중 전환점을 바꿔 보고 싶으면 첫 번째 min-width: 768px만 900px로 수정합니다. 그러면 두 열이 시작되는 너비도 900px로 바뀝니다. 비교를 마치면 768px로 되돌려 원래 예상 결과와 다시 대조하세요.
작은 화면에서 배치가 깨질 때 점검하기
- viewport 메타 태그를 확인합니다. 빠져 있으면 모바일 브라우저가 넓은 가상 뷰포트를 사용해 의도한 조건이 적용되지 않는 것처럼 보일 수 있습니다.
- 남아 있는 고정 너비를 찾습니다. 큰
width,min-width, 고정 크기 이미지나 긴 코드가 어느 영역을 밀어내는지 요소 검사로 확인합니다. - 조건과 덮어쓰기 순서를 확인합니다. 1,100px 이상에서는 두 미디어 쿼리가 모두 적용됩니다. 다른 규칙의 높은 명시도나
!important때문에 열 설정이 덮어써졌는지도 살펴봅니다. - 실제 콘텐츠와 조작을 확인합니다. 긴 제목, 큰 글자와 브라우저 확대 상태, 키보드 이동도 점검합니다. 화면에 맞추기 위해 중요한 내용을 숨기거나 글자를 지나치게 줄이는 방식은 피합니다.
미디어 쿼리의 조건과 결합 방식은 MDN의 미디어 쿼리 사용 설명에서 확인할 수 있습니다. 반응형 웹디자인 안내는 유동적인 배치와 콘텐츠를 기준으로 전환점을 정하는 방법을 설명합니다.





