레이아웃이란?
레이아웃은 화면 위에 요소들을 어떻게 배치할 것인가를 결정하는 작업. HTML 구조 + CSS 배치 기법의 조합으로 완성됨.
현대 CSS에서 레이아웃을 다루는 핵심 기술은 크게 4가지.
1.
Normal Flow — 기본 흐름
2.
Flexbox — 1차원 정렬
3.
Grid — 2차원 격자
4.
Position — 절대/고정 배치
1. Normal Flow (기본 흐름)
CSS를 아무것도 적용하지 않았을 때의 기본 배치 규칙.
•
Block 요소 (div, p, h1 등): 가로 전체를 차지하고 아래로 쌓임
•
Inline 요소 (span, a, img 등): 콘텐츠 크기만큼만 차지하고 옆으로 나열
•
Inline-block: 인라인처럼 옆으로 나열되지만 width/height 지정 가능
<!-- Block vs Inline 예시 -->
<div style="background: #e3f2fd;">Block 요소 — 가로 전체 차지</div>
<div style="background: #fff3e0;">Block 요소 — 아래로 쌓임</div>
<span style="background: #e8f5e9;">Inline</span>
<span style="background: #fce4ec;">나란히 배치</span>
HTML
복사
2. Flexbox — 1차원 레이아웃
가로 또는 세로 한 방향으로 요소를 정렬할 때 사용. 네비게이션 바, 카드 목록, 버튼 그룹에 최적.
핵심 속성
/* 컨테이너 속성 */
.container {
display: flex;
/* 주축 방향 */
flex-direction: row; /* row | column | row-reverse | column-reverse */
/* 주축 정렬 */
justify-content: flex-start; /* flex-start | center | flex-end | space-between | space-around | space-evenly */
/* 교차축 정렬 */
align-items: stretch; /* stretch | flex-start | center | flex-end | baseline */
/* 줄 바꿈 */
flex-wrap: nowrap; /* nowrap | wrap | wrap-reverse */
/* gap */
gap: 16px;
}
/* 아이템 속성 */
.item {
flex: 1; /* flex-grow: 1, flex-shrink: 1, flex-basis: 0 */
flex-grow: 1; /* 남은 공간 차지 비율 */
flex-shrink: 0; /* 0이면 줄어들지 않음 */
flex-basis: 200px; /* 기준 크기 */
align-self: center; /* 개별 교차축 정렬 */
order: 1; /* 시각적 순서 변경 */
}
CSS
복사
실전 예제 — 네비게이션 바
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 24px;
height: 60px;
background: #1a1a2e;
color: white;
}
.nav-logo {
font-size: 20px;
font-weight: bold;
color: #e94560;
}
.nav-menu {
display: flex;
gap: 32px;
list-style: none;
}
.nav-menu a {
color: #ccc;
text-decoration: none;
font-size: 14px;
transition: color 0.2s;
}
.nav-menu a:hover { color: white; }
.nav-actions {
display: flex;
gap: 12px;
}
.btn {
padding: 8px 20px;
border-radius: 6px;
border: none;
cursor: pointer;
font-size: 14px;
}
.btn-primary { background: #e94560; color: white; }
.btn-ghost { background: transparent; color: white; border: 1px solid #555; }
</style>
</head>
<body>
<nav class="navbar">
<div class="nav-logo">MyBrand</div>
<ul class="nav-menu">
<li><a href="#">홈</a></li>
<li><a href="#">서비스</a></li>
<li><a href="#">가격</a></li>
<li><a href="#">문의</a></li>
</ul>
<div class="nav-actions">
<button class="btn btn-ghost">로그인</button>
<button class="btn btn-primary">시작하기</button>
</div>
</nav>
</body>
</html>
HTML
복사
실전 예제 — 카드 목록 (자동 줄 바꿈)
.card-list {
display: flex;
flex-wrap: wrap;
gap: 20px;
padding: 24px;
}
.card {
flex: 1 1 280px; /* 최소 280px, 여유 공간 있으면 늘어남 */
max-width: 360px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
padding: 20px;
}
CSS
복사
3. CSS Grid — 2차원 레이아웃
가로와 세로를 동시에 제어. 페이지 전체 레이아웃, 대시보드, 갤러리에 최적.
핵심 속성
.grid-container {
display: grid;
/* 열 정의 */
grid-template-columns: 240px 1fr 1fr; /* 고정 + 유동 */
grid-template-columns: repeat(3, 1fr); /* 균등 3열 */
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); /* 반응형 */
/* 행 정의 */
grid-template-rows: 60px 1fr auto;
/* 간격 */
gap: 20px; /* row-gap + column-gap */
row-gap: 16px;
column-gap: 24px;
}
/* 셀 병합 — 아이템 속성 */
.header {
grid-column: 1 / -1; /* 첫 번째 ~ 마지막 열까지 */
grid-row: 1;
}
.sidebar {
grid-column: 1;
grid-row: 2 / 4; /* 2행 ~ 4행까지 */
}
.main-content {
grid-column: 2 / -1;
grid-row: 2;
}
CSS
복사
실전 예제 — 전형적인 페이지 레이아웃
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: 60px 1fr 50px;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
font-family: system-ui, sans-serif;
}
header {
grid-area: header;
background: #1a1a2e;
color: white;
display: flex;
align-items: center;
padding: 0 24px;
font-size: 18px;
font-weight: bold;
}
.sidebar {
grid-area: sidebar;
background: #f8f9fa;
padding: 20px;
border-right: 1px solid #e9ecef;
}
.sidebar ul {
list-style: none;
display: flex;
flex-direction: column;
gap: 8px;
}
.sidebar a {
display: block;
padding: 10px 16px;
border-radius: 8px;
text-decoration: none;
color: #495057;
font-size: 14px;
}
.sidebar a:hover,
.sidebar a.active {
background: #e9ecef;
color: #212529;
}
main {
grid-area: main;
padding: 32px;
overflow-y: auto;
}
footer {
grid-area: footer;
background: #343a40;
color: #adb5bd;
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
}
</style>
</head>
<body>
<header>⚡ MyApp</header>
<aside class="sidebar">
<ul>
<li><a href="#" class="active">대시보드</a></li>
<li><a href="#">사용자 관리</a></li>
<li><a href="#">통계</a></li>
<li><a href="#">설정</a></li>
</ul>
</aside>
<main>
<h1>대시보드</h1>
<p>메인 콘텐츠 영역</p>
</main>
<footer>© 2026 MyApp. All rights reserved.</footer>
</body>
</html>
HTML
복사
실전 예제 — 반응형 카드 갤러리
.gallery {
display: grid;
/* 최소 280px, 넘치면 자동으로 열 추가/제거 */
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
padding: 24px;
}
/* 특정 카드를 크게 표시 */
.gallery .featured {
grid-column: span 2;
grid-row: span 2;
}
CSS
복사
4. Position — 절대/고정 배치
position 속성 비교
값 | 설명 | 기준점 |
static | 기본값. normal flow | — |
relative | 원래 자리를 유지하며 이동 | 자기 자신 |
absolute | normal flow에서 빠져나옴 | 가장 가까운 positioned 부모 |
fixed | 뷰포트 기준 고정 | 뷰포트 |
sticky | 스크롤 시 특정 지점에서 fixed 전환 | 스크롤 컨테이너 |
실전 예제 — 모달, 툴팁, 드롭다운
/* 모달 오버레이 */
.modal-overlay {
position: fixed;
inset: 0; /* top: 0; right: 0; bottom: 0; left: 0 축약 */
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal {
background: white;
border-radius: 16px;
padding: 32px;
width: 90%;
max-width: 480px;
position: relative;
}
.modal-close {
position: absolute;
top: 16px;
right: 16px;
cursor: pointer;
}
/* sticky 헤더 */
.sticky-header {
position: sticky;
top: 0;
z-index: 100;
background: white;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
/* 툴팁 */
.tooltip-wrapper {
position: relative;
display: inline-block;
}
.tooltip {
position: absolute;
bottom: calc(100% + 8px);
left: 50%;
transform: translateX(-50%);
background: #333;
color: white;
padding: 6px 12px;
border-radius: 6px;
font-size: 12px;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
}
.tooltip-wrapper:hover .tooltip {
opacity: 1;
}
CSS
복사
5. 반응형 레이아웃 — Media Query
화면 크기에 따라 레이아웃을 다르게 적용.
브레이크포인트 기준 (일반적)
기기 | 범위 | 기준 |
Mobile | ~ 767px | 단일 열 |
Tablet | 768px ~ 1023px | 2열 |
Desktop | 1024px ~ | 3열 이상 |
Mobile-First 접근법
/* 기본: 모바일 (1열) */
.container {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
padding: 16px;
}
/* 태블릿 이상 (2열) */
@media (min-width: 768px) {
.container {
grid-template-columns: repeat(2, 1fr);
padding: 24px;
}
}
/* 데스크탑 이상 (3열) */
@media (min-width: 1024px) {
.container {
grid-template-columns: repeat(3, 1fr);
padding: 32px;
}
}
CSS
복사
반응형 네비게이션 (모바일 햄버거 메뉴)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
height: 56px;
background: #1a1a2e;
color: white;
position: sticky;
top: 0;
z-index: 100;
}
.nav-logo { font-weight: bold; font-size: 18px; color: #e94560; }
.hamburger {
display: flex;
flex-direction: column;
gap: 5px;
cursor: pointer;
padding: 4px;
}
.hamburger span {
display: block;
width: 24px;
height: 2px;
background: white;
transition: all 0.3s;
}
/* 모바일: 드로어 메뉴 */
.nav-menu {
position: fixed;
top: 56px;
left: 0;
width: 100%;
background: #16213e;
flex-direction: column;
padding: 16px 20px;
gap: 4px;
list-style: none;
transform: translateY(-110%);
transition: transform 0.3s ease;
z-index: 99;
}
.nav-menu.open {
transform: translateY(0);
}
.nav-menu a {
display: block;
padding: 12px 16px;
color: #ccc;
text-decoration: none;
border-radius: 8px;
}
.nav-menu a:hover { background: #0f3460; color: white; }
/* 데스크탑: 일반 메뉴 */
@media (min-width: 768px) {
.hamburger { display: none; }
.nav-menu {
position: static;
display: flex !important;
flex-direction: row;
transform: none;
background: transparent;
padding: 0;
gap: 8px;
}
}
</style>
</head>
<body>
<nav class="navbar">
<div class="nav-logo">MyBrand</div>
<div class="hamburger" onclick="this.nextElementSibling.classList.toggle('open')">
<span></span><span></span><span></span>
</div>
<ul class="nav-menu">
<li><a href="#">홈</a></li>
<li><a href="#">서비스</a></li>
<li><a href="#">가격</a></li>
<li><a href="#">문의</a></li>
</ul>
</nav>
</body>
</html>
HTML
복사
6. 실전 — 완성형 랜딩 페이지
Flex + Grid + Position + Media Query를 모두 조합한 실전 예제.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>랜딩 페이지</title>
<style>
:root {
--primary: #6c63ff;
--dark: #1a1a2e;
--text: #333;
--gray: #f8f9fa;
--radius: 12px;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', system-ui, sans-serif; color: var(--text); }
/* ── 네비게이션 ── */
.navbar {
position: sticky;
top: 0;
z-index: 100;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 48px;
height: 64px;
background: rgba(255,255,255,0.95);
backdrop-filter: blur(10px);
border-bottom: 1px solid #e9ecef;
}
.logo { font-weight: 700; font-size: 20px; color: var(--primary); }
.nav-links {
display: flex;
gap: 32px;
list-style: none;
}
.nav-links a {
text-decoration: none;
color: #666;
font-size: 15px;
}
.btn {
padding: 10px 24px;
border-radius: 8px;
border: none;
cursor: pointer;
font-size: 15px;
font-weight: 500;
}
.btn-primary { background: var(--primary); color: white; }
/* ── 히어로 섹션 ── */
.hero {
display: flex;
align-items: center;
justify-content: space-between;
padding: 80px 48px;
min-height: calc(100vh - 64px);
gap: 48px;
}
.hero-text { flex: 1; max-width: 560px; }
.hero-tag {
display: inline-block;
background: #ede9ff;
color: var(--primary);
padding: 6px 14px;
border-radius: 20px;
font-size: 13px;
font-weight: 500;
margin-bottom: 20px;
}
.hero h1 {
font-size: clamp(32px, 5vw, 56px);
line-height: 1.2;
margin-bottom: 20px;
color: var(--dark);
}
.hero p {
font-size: 18px;
color: #666;
line-height: 1.7;
margin-bottom: 32px;
}
.hero-actions { display: flex; gap: 16px; }
.btn-outline {
background: transparent;
border: 2px solid var(--primary);
color: var(--primary);
}
.hero-visual {
flex: 1;
max-width: 480px;
aspect-ratio: 4/3;
background: linear-gradient(135deg, #ede9ff 0%, #d1ecff 100%);
border-radius: 24px;
display: flex;
align-items: center;
justify-content: center;
font-size: 80px;
}
/* ── 피처 섹션 ── */
.features {
padding: 80px 48px;
background: var(--gray);
}
.section-title {
text-align: center;
font-size: 36px;
font-weight: 700;
margin-bottom: 48px;
color: var(--dark);
}
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
}
.feature-card {
background: white;
padding: 32px;
border-radius: var(--radius);
box-shadow: 0 2px 16px rgba(0,0,0,0.06);
transition: transform 0.2s, box-shadow 0.2s;
}
.feature-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 32px rgba(0,0,0,0.12);
}
.feature-icon {
font-size: 36px;
margin-bottom: 16px;
}
.feature-card h3 {
font-size: 18px;
margin-bottom: 10px;
color: var(--dark);
}
.feature-card p { color: #666; line-height: 1.6; font-size: 15px; }
/* ── 반응형 ── */
@media (max-width: 768px) {
.navbar { padding: 0 20px; }
.nav-links { display: none; }
.hero {
flex-direction: column;
padding: 48px 20px;
min-height: auto;
text-align: center;
}
.hero-actions { justify-content: center; }
.hero-visual { width: 100%; }
.features { padding: 48px 20px; }
}
</style>
</head>
<body>
<nav class="navbar">
<div class="logo">⚡ DevKit</div>
<ul class="nav-links">
<li><a href="#">기능</a></li>
<li><a href="#">가격</a></li>
<li><a href="#">문서</a></li>
</ul>
<button class="btn btn-primary">무료 시작</button>
</nav>
<section class="hero">
<div class="hero-text">
<span class="hero-tag">🚀 새로운 버전 출시</span>
<h1>개발을 더 빠르게, 더 스마트하게</h1>
<p>반복적인 작업은 자동화하고 핵심 로직에만 집중하세요. 생산성을 10배 높여드립니다.</p>
<div class="hero-actions">
<button class="btn btn-primary">지금 시작하기</button>
<button class="btn btn-outline">데모 보기</button>
</div>
</div>
<div class="hero-visual">🛠️</div>
</section>
<section class="features">
<h2 class="section-title">핵심 기능</h2>
<div class="feature-grid">
<div class="feature-card">
<div class="feature-icon">⚡</div>
<h3>빠른 빌드</h3>
<p>최적화된 빌드 파이프라인으로 배포 시간을 최소화합니다.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔒</div>
<h3>보안 강화</h3>
<p>자동화된 보안 스캔으로 취약점을 사전에 탐지합니다.</p>
</div>
<div class="feature-card">
<div class="feature-icon">📊</div>
<h3>실시간 모니터링</h3>
<p>애플리케이션 상태를 실시간으로 추적하고 알림을 받으세요.</p>
</div>
</div>
</section>
</body>
</html>
HTML
복사
7. 자주 쓰는 레이아웃 패턴 치트시트
수직/수평 완전 중앙 정렬
/* 방법 1: Flex */
.center {
display: flex;
align-items: center;
justify-content: center;
}
/* 방법 2: Grid */
.center {
display: grid;
place-items: center; /* align-items + justify-items 축약 */
}
/* 방법 3: absolute + transform */
.center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
CSS
복사
고정 사이드바 + 유동 콘텐츠
.layout {
display: grid;
grid-template-columns: 260px 1fr;
min-height: 100vh;
}
.sidebar {
position: sticky;
top: 0;
height: 100vh;
overflow-y: auto;
}
CSS
복사
Holy Grail 레이아웃
body {
display: grid;
grid-template:
"header" 60px
"main" 1fr
"footer" 50px
/ 1fr;
min-height: 100vh;
}
/* 3열 버전 */
.main-area {
display: grid;
grid-template-columns: 200px 1fr 200px;
gap: 24px;
}
CSS
복사
화면 꽉 채우기 (Full Viewport)
.full-screen {
width: 100vw;
height: 100vh;
/* 또는 */
min-height: 100dvh; /* 모바일 브라우저 주소창 고려 */
}
CSS
복사
정리 — 언제 무엇을 쓸까?
상황 | 추천 기법 |
요소를 가로로 나열 | Flexbox (flex-direction: row) |
요소를 세로로 나열 | Flexbox (flex-direction: column) |
페이지 전체 골격 | Grid (grid-template-areas) |
카드 갤러리 (반응형) | Grid (auto-fill • minmax) |
중앙 정렬 | place-items: center or Flex |
모달/오버레이 | position: fixed • z-index |
스크롤 시 고정 헤더 | position: sticky |
툴팁/드롭다운 | position: absolute on relative 부모 |
Flex는 1차원 (한 줄), Grid는 2차원 (행+열). 이 구분만 확실히 해도 레이아웃 선택이 명확해짐.

