CSS Flexbox vs Grid: 언제 무엇을 사용할까
· 12분 읽기
목차
CSS Flexbox와 Grid 중 선택하는 것은 부담스러울 수 있습니다. 특히 둘 다 같은 레이아웃 문제를 해결할 수 있어 보일 때 더욱 그렇습니다. 사실 이들은 서로 다른 목적을 위해 설계되었으며, 각각의 강점을 이해하면 더 효과적인 개발자가 될 수 있습니다.
이 가이드는 핵심 개념부터 실제 적용까지 Flexbox와 Grid에 대해 알아야 할 모든 것을 다룹니다. 끝까지 읽으면 어떤 레이아웃 시나리오에서든 정확히 어떤 도구를 사용해야 할지 알게 될 것입니다.
Flexbox 기초 (1차원 레이아웃)
Flexbox는 1차원 레이아웃을 위해 설계되었습니다 — 항목을 단일 행이나 열로 배열합니다. 한 축을 따라 공간을 분배하고 항목을 정렬하는 데 탁월하여 내비게이션 바, 버튼 그룹, 단일 방향으로 흐르는 콘텐츠에 완벽합니다.
핵심 개념
모든 Flexbox 레이아웃에는 플렉스 컨테이너(부모)와 플렉스 항목(자식)이 있습니다. 컨테이너는 항목의 방향, 줄바꿈, 정렬을 제어합니다:
/* 플렉스 컨테이너 */
.container {
display: flex;
flex-direction: row; /* row | row-reverse | column | column-reverse */
justify-content: center; /* 주축 정렬 */
align-items: center; /* 교차축 정렬 */
gap: 1rem; /* 항목 간 간격 */
flex-wrap: wrap; /* 항목이 다음 줄로 넘어가도록 허용 */
}
/* 플렉스 항목 */
.item {
flex: 1; /* 사용 가능한 공간을 채우도록 확장 */
/* 다음의 축약형: flex-grow: 1; flex-shrink: 1; flex-basis: 0; */
}
.item-fixed {
flex: 0 0 200px; /* 확장 안 함, 축소 안 함, 200px 너비 */
}
주축과 교차축 이해하기
Flexbox를 마스터하는 핵심은 두 축을 이해하는 것입니다. 주축은 flex-direction으로 설정된 방향으로 실행됩니다(row는 가로, column은 세로). 교차축은 주축에 수직으로 실행됩니다.
이 축 시스템은 어떤 속성이 어떤 차원을 제어하는지 결정합니다. justify-content는 항상 주축에서 작동하고, align-items는 교차축에서 작동합니다.
정렬 속성
/* 주축 (row 방향에서 가로) */
.container {
justify-content: flex-start; /* 기본값: 항목을 시작점에 배치 */
justify-content: flex-end; /* 항목을 끝점에 배치 */
justify-content: center; /* 항목을 중앙에 배치 */
justify-content: space-between;/* 항목 사이에 동일한 간격 */
justify-content: space-around; /* 항목 주위에 동일한 간격 */
justify-content: space-evenly; /* 모든 곳에 동일한 간격 */
}
/* 교차축 (row 방향에서 세로) */
.container {
align-items: stretch; /* 기본값: 컨테이너를 채우도록 늘림 */
align-items: flex-start; /* 위쪽 정렬 */
align-items: flex-end; /* 아래쪽 정렬 */
align-items: center; /* 세로 중앙 정렬 */
align-items: baseline; /* 텍스트 기준선 정렬 */
}
Flex 속성 설명
flex 속성은 세 가지 속성의 축약형입니다: flex-grow, flex-shrink, flex-basis. 이들을 개별적으로 이해하면 더 정확한 레이아웃을 작성할 수 있습니다.
- flex-grow: 다른 항목에 비해 항목이 얼마나 확장되어야 하는지 (기본값: 0)
- flex-shrink: 공간이 제한될 때 항목이 얼마나 축소되어야 하는지 (기본값: 1)
- flex-basis: 확장 또는 축소 전 초기 크기 (기본값: auto)
.item-grow {
flex: 1; /* 다음과 동일: 1 1 0% */
}
.item-fixed {
flex: 0 0 200px; /* 확장 또는 축소 안 함, 200px 유지 */
}
.item-shrink {
flex: 0 1 auto; /* 확장 안 함, 필요시 축소 가능 */
}
프로 팁: 항목이 공간을 균등하게 공유하도록 하려면 flex: 1을 사용하고, 항목이 확장이나 축소 없이 자연스러운 크기를 유지하도록 하려면 flex: 0 0 auto를 사용하세요.
Grid 기초 (2차원 레이아웃)
CSS Grid는 2차원 레이아웃을 위해 만들어졌습니다 — 행과 열을 동시에 제어합니다. 페이지 레벨 레이아웃, 카드 그리드, 두 차원 모두에 대한 정확한 제어가 필요한 모든 디자인에 적합한 선택입니다.
핵심 개념
Grid 레이아웃은 그리드 컨테이너와 그리드 항목으로 구성됩니다. Flexbox와 달리 Grid는 명시적인 트랙(행과 열)을 정의하고 해당 구조 내 어디에나 항목을 배치할 수 있습니다:
/* 그리드 컨테이너 */
.container {
display: grid;
grid-template-columns: 200px 1fr 1fr; /* 3개 열 */
grid-template-rows: auto 1fr auto; /* 3개 행 */
gap: 1rem; /* 셀 간 간격 */
grid-auto-flow: row; /* 자동 배치 항목이 흐르는 방식 */
}
/* 그리드 항목 */
.item {
grid-column: 1 / 3; /* 열 라인 1에서 3까지 확장 */
grid-row: 1 / 2; /* 첫 번째 행 차지 */
}
.item-area {
grid-area: header; /* 명명된 영역에 배치 */
}
그리드 라인과 트랙 이해하기
Grid는 트랙 사이에 번호가 매겨진 라인을 생성합니다. 3열 그리드는 4개의 세로 라인(1, 2, 3, 4)을 가집니다. 항목은 어떤 라인 사이에 걸쳐 있는지 지정하여 배치됩니다.
트랙은 라인 사이의 공간입니다 — 실제 열과 행입니다. 고정 단위(px), 유연한 단위(fr), 또는 콘텐츠 기반 크기(auto, min-content, max-content)로 크기를 지정할 수 있습니다.
FR 단위
fr 단위는 Grid의 강력한 기능입니다. 사용 가능한 공간의 분수를 나타내며, 트랙 간에 비례적으로 분배합니다:
.container {
grid-template-columns: 1fr 2fr 1fr; /* 중간 열이 2배 공간 차지 */
grid-template-columns: 200px 1fr; /* 고정 사이드바, 유연한 콘텐츠 */
grid-template-columns: repeat(3, 1fr); /* 3개의 동일한 열 */
}
명명된 그리드 영역
Grid의 템플릿 영역 기능을 사용하면 ASCII 아트와 같은 구문을 사용하여 레이아웃을 만들 수 있어 복잡한 레이아웃을 읽기 쉽게 만듭니다:
.container {
display: grid;
grid-template-areas:
"header header header"
"sidebar content content"
"footer footer footer";
grid-template-columns: 200px 1fr 1fr;
grid-template-rows: auto 1fr auto;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
자동 배치와 그리드 자동 흐름
Grid는 명시적으로 배치하지 않은 항목을 자동으로 배치할 수 있습니다. grid-auto-flow 속성은 항목이 행을 먼저 채울지(기본값) 열을 먼저 채울지 제어합니다:
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-flow: dense; /* 작은 항목으로 빈 공간 채우기 */
}
프로 팁: 빈 공간을 채우고 싶은 메이슨리 같은 레이아웃에는 grid-auto-flow: dense를 사용하세요. 하지만 이것이 항목의 시각적 순서를 변경하여 접근성에 영향을 줄 수 있다는 점을 유의하세요.
나란히 비교
Flexbox와 Grid를 주요 차원에서 비교하여 근본적인 차이점을 이해해 봅시다:
| 기능 | Flexbox | Grid |
|---|---|---|
| 차원 | 1차원 (행 또는 열) | 2차원 (행과 열) |
| 콘텐츠 중심 | 예 - 항목이 크기 제어 | 아니오 - 컨테이너가 구조 정의 |
| 레이아웃 방향 | 한 번에 단일 축 | 두 축 동시에 |
| 항목 배치 | 순차적 (소스 순서) | 명시적 배치 가능 |
| 정렬 | 단일 축에서 강력함 | 두 축 모두에서 강력함 |
| 간격 지원 | 예 (최신 브라우저) | 예 (처음부터) |
| 최적 용도 | 컴포넌트, 내비게이션, 툴바 | 페이지 레이아웃, 카드 그리드, 대시보드 |
| 학습 곡선 | 보통 | 초기에 더 가파름 |
개념적 차이점
근본적인 차이는 제어로 귀결됩니다. Flexbox는 콘텐츠 우선입니다 — 항목이 콘텐츠 크기에 따라 레이아웃에 영향을 줍니다. Grid는 레이아웃 우선입니다 — 먼저 구조를 정의한 다음 콘텐츠를 배치합니다.
Flexbox는 측정하는 대상에 맞춰 조정되는 유연한 자처럼 생각하세요. Grid는 미리 구조를 결정하는 모눈종이에 가깝습니다.
| 시나리오 | Flexbox 접근법 | Grid 접근법 |
|---|---|---|
| 내비게이션 바 | 자연스러운 적합 - 행의 항목 | 과도함 - 너무 많은 구조 |
| 카드 그리드 | 가능하지만 줄바꿈이 어색함 | 완벽함 - 명시적인 행과 열 |
| 폼 레이아웃 | 간단한 폼에 좋음 | 복잡한 다중 열 폼에 더 좋음 |
| 페이지 레이아웃 | 여러 컨테이너 중첩 필요 | 단일 컨테이너로 처리 가능 |
| 콘텐츠 중앙 정렬 | 훌륭함 - 간단하고 직관적 | 역시 훌륭함 - place-items: center |
Flexbox를 사용해야 할 때
Flexbox는 콘텐츠가 단일 방향으로 흐르고 항목이 사용 가능한 공간에 적응해야 하는 시나리오에서 빛을 발합니다. Flexbox가 최선의 선택인 상황은 다음과 같습니다:
내비게이션 바와 메뉴
내비게이션 컴포넌트는 Flexbox의 대표적인 사례입니다. 항목이 자연스럽게 행으로 흐르고, 종종 공간을 균등하게 분배하거나 반대쪽 끝에 정렬하고 싶을 때가 있습니다:
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
.nav-links {
display: flex;
gap: 2rem;
list-style: none;
}
버튼 그룹과 툴바
나란히 배치되어야 하는 버튼이나 도구 모음이 있을 때 Flexbox는 간격과 정렬을 완벽하게 처리합니다:
.button-group {
display: flex;
gap: 0.5rem;
}
.toolbar {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 1rem;
}
미디어 객체
고전적인 미디어 객체 패턴(한쪽에 이미지, 다른 쪽에 콘텐츠)은 Flexbox로 간단합니다:
.media {
display: flex;
gap: 1rem;
}
.media-image {
flex: 0 0 100px; /* 고정 너비 이미지 */
}
.media-content {
flex: 1; /* 콘텐츠가 남은 공간 차지 */
}
폼 컨트롤
레이블, 입력, 버튼이 행으로 배치되는 입력 그룹은 Flexbox에 완벽합니다:
.input-group {
display: flex;
gap: 0.5rem;
}
.input-group input {
flex: 1; /* 입력이 공간을 채우도록 확장 */
}
.input-group button {
flex: 0 0 auto; /* 버튼은 자연스러운 크기 유지 */
}