지난 포스팅에서 배운 Flexbox 개념을 활용해서 실무에서 자주 쓰이는 전체 페이지 레이아웃을 만들어봅니다.
flex-grow, flex-basis, flex-shrink를 실제로 적용하면서 각 속성의 역할을 체득해봅시다!
┌─────────────────────────────────┐
│ header │ ← 고정 높이
├──────┬──────────────────┬───────┤
│ │ │ │
│ nav │ main │ aside │ ← 남은 공간 전부
│150px │ (flex-grow:1) │ 120px │
│ │ │ │
├──────┴──────────────────┴───────┤
│ footer │ ← 고정 높이
└─────────────────────────────────┘
핵심 아이디어:
container를 세로 Flex로,content를 가로 Flex로 만들어 중첩 Flexbox 구조를 완성합니다.
<div class="container">
<header>
<h1>레이아웃 배우기</h1>
</header>
<section class="content">
<nav>
<ul>
<li><a href="#">메뉴 아이템 1</a></li>
<li><a href="#">메뉴 아이템 2</a></li>
<li><a href="#">메뉴 아이템 3</a></li>
<li><a href="#">메뉴 아이템 4</a></li>
</ul>
</nav>
<main>
(1절) 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세
</main>
<aside>
추가적인 내용
</aside>
</section>
<footer>
<a href="#">SBS 아카데미</a>
</footer>
</div>
/* 기본 초기화 */
body, h1 {
margin: 0;
}
/* 전체 컨테이너 — 세로 Flex */
.container {
display: flex;
flex-direction: column;
min-height: 100dvh;
background-color: darkcyan;
}
/* 헤더 — 고정 높이 */
.container > header {
flex-grow: 0;
background-color: red;
}
/* 콘텐츠 영역 — 가로 Flex + 남은 공간 전부 */
.container > .content {
display: flex;
flex-direction: row;
flex-grow: 1;
}
/* 왼쪽 사이드 메뉴 — 고정 너비 */
.container > .content > nav {
flex-basis: 150px;
flex-shrink: 0;
background-color: gold;
}
/* 메인 콘텐츠 — 나머지 공간 전부 */
.container > .content > main {
flex-grow: 1;
flex-shrink: 1;
background-color: pink;
}
/* 오른쪽 부가 정보 — 고정 너비 */
.container > .content > aside {
flex-basis: 120px;
flex-shrink: 0;
background-color: purple;
}
/* 푸터 — 고정 높이 + 가운데 정렬 */
.container > footer {
flex-grow: 0;
background-color: green;
display: flex;
justify-content: center;
}
<div class="container">
<header>
<h1>레이아웃 배우기</h1>
</header>
<section class="content">
<nav>
<ul>
<li><a href="#">메뉴 아이템 1</a></li>
<li><a href="#">메뉴 아이템 2</a></li>
<li><a href="#">메뉴 아이템 3</a></li>
<li><a href="#">메뉴 아이템 4</a></li>
</ul>
</nav>
<main>
(1절) 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세
</main>
<aside>
추가적인 내용
</aside>
</section>
<footer>
<a href="#">SBS 아카데미</a>
</footer>
</div>
.container ← 전체 페이지 감싸기 (세로 Flex)
├── header ← 상단 헤더
├── .content ← 중간 콘텐츠 영역 (가로 Flex)
│ ├── nav ← 왼쪽 사이드 메뉴
│ ├── main ← 메인 콘텐츠
│ └── aside ← 오른쪽 부가 정보
└── footer ← 하단 푸터
body, h1 {
margin: 0; /* 브라우저 기본 여백 제거 */
}
브라우저마다
body,h1등에 기본margin이 있습니다.
레이아웃 작업 전에 먼저 초기화하지 않으면 의도치 않은 여백이 생깁니다.
.container {
display: flex;
flex-direction: column; /* 자식들을 세로로 쌓기 */
min-height: 100dvh; /* 최소 높이 = 화면 전체 높이 */
background-color: darkcyan;
}
| 속성 | 값 | 역할 |
|---|---|---|
flex-direction: column | column | header → content → footer 순으로 세로 배치 |
min-height: 100dvh | 100dvh | 콘텐츠가 적어도 화면을 꽉 채움 |
dvh란? Dynamic Viewport Height의 약자로, 모바일 브라우저의 주소창 높이까지 고려한 화면 높이입니다.vh보다 더 정확합니다.
.container > header {
flex-grow: 0; /* 기본값 — 남은 공간을 차지하지 않음 */
background-color: red;
}
.container > footer {
flex-grow: 0; /* 기본값 — 남은 공간을 차지하지 않음 */
background-color: green;
display: flex;
justify-content: center; /* 푸터 내용 가운데 정렬 */
}
flex-grow: 0은 기본값이라 생략해도 동일하게 동작합니다.
직접 써놓으면 "이건 의도적으로 늘어나지 않게 한 것"이라는 의도를 코드로 표현할 수 있습니다.
.container > .content {
display: flex;
flex-direction: row; /* 자식들을 가로로 배치 (기본값) */
flex-grow: 1; /* header/footer를 제외한 남은 공간 전부 차지 */
}
flex-grow: 1이 핵심입니다.
header와 footer는flex-grow: 0(고정)이고, content만flex-grow: 1이므로
화면 높이에서 header + footer를 뺀 나머지를 content가 전부 차지합니다.
화면 전체 높이 (100dvh)
├── header → flex-grow: 0 (내용 높이만큼)
├── content → flex-grow: 1 (나머지 전부 ← 이게 핵심!)
└── footer → flex-grow: 0 (내용 높이만큼)
.container > .content > nav {
flex-basis: 150px; /* 기본 너비 150px */
flex-shrink: 0; /* 화면이 좁아져도 줄어들지 않음 */
background-color: gold;
}
.container > .content > aside {
flex-basis: 120px; /* 기본 너비 120px */
flex-shrink: 0; /* 화면이 좁아져도 줄어들지 않음 */
background-color: purple;
}
| 속성 | 역할 |
|---|---|
flex-basis | Flex 아이템의 기본 크기 설정 (너비 역할) |
flex-shrink: 0 | 공간이 부족해도 줄어들지 않음 |
flex-shrink: 1 | 공간이 부족하면 비율대로 줄어듦 (기본값) |
flex-shrink: 0을 빼보면 화면을 좁혔을 때 nav와 aside가 쪼그라드는 걸 확인할 수 있습니다.
.container > .content > main {
flex-grow: 1; /* nav와 aside를 제외한 나머지 공간 전부 */
flex-shrink: 1; /* 공간 부족 시 줄어들 수 있음 (기본값) */
background-color: pink;
}
content 가로 공간
├── nav → flex-basis: 150px (고정)
├── main → flex-grow: 1 (나머지 전부 ← 핵심!)
└── aside → flex-basis: 120px (고정)
각 속성을 지워보면서 변화를 눈으로 확인해보세요!
| 지워볼 속성 | 기본값 | 지우면 어떻게 되나? |
|---|---|---|
header의 flex-grow: 0 | 0 | 변화 없음 (기본값이라서) |
nav의 flex-shrink: 0 | 1 | 화면을 좁히면 nav가 쪼그라듦 |
aside의 flex-shrink: 0 | 1 | 화면을 좁히면 aside가 쪼그라듦 |
main의 flex-shrink: 1 | 1 | 변화 없음 (기본값이라서) |
content의 flex-grow: 1 | 0 | content가 높이를 차지 못함 |
📌 중첩 Flexbox — container(세로 Flex) 안에 content(가로 Flex)를 넣어 2D 레이아웃을 완성합니다.
📌 flex-grow: 1 — header/footer는 0(고정), content만 1로 설정해 남은 세로 공간을 content가 가져갑니다.
📌 flex-basis — nav와 aside의 고정 너비를 설정합니다. width와 비슷하지만 Flex 환경에 최적화된 속성입니다.
📌 flex-shrink: 0 — nav와 aside가 화면이 좁아져도 줄어들지 않게 고정합니다. 1이 기본값이라 명시적으로 0을 써야 합니다.
📌 min-height: 100dvh — 콘텐츠가 적어도 화면 전체를 채우는 레이아웃을 만들 때 사용합니다.