Backend
home
🎨

웹 사이트 레이아웃 완전 정복 — CSS 핵심 기법과 실전 코드

생성일
2026/04/26 12:45
태그
HTML
CSS

레이아웃이란?

레이아웃은 화면 위에 요소들을 어떻게 배치할 것인가를 결정하는 작업. 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-fillminmax)
중앙 정렬
place-items: center or Flex
모달/오버레이
position: fixedz-index
스크롤 시 고정 헤더
position: sticky
툴팁/드롭다운
position: absolute on relative 부모
Flex는 1차원 (한 줄), Grid는 2차원 (행+열). 이 구분만 확실히 해도 레이아웃 선택이 명확해짐.