CSS 레이아웃 정리: Flexbox vs Grid·subgrid 비교
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
목차
CSS 레이아웃은 웹 개발에서 가장 많이 막히는 부분 중 하나입니다. Flexbox와 Grid 둘 다 배웠는데 막상 코딩할 때 어느 것을 써야 할지 모르겠다면,
이 가이드가 명확한 기준을 드립니다.
이 글은 Flexbox와 Grid의 핵심 개념, 둘의 정확한 차이, 실무 패턴 레시피,
subgrid·container queries 같은 최신 기능, Tailwind CSS 대응, 그리고 성능 고려사항까지 한 번에 정리합니다.
Flexbox vs Grid: 한 줄 요약#
- Flexbox: 한 방향(행 또는 열) 정렬에 강한 1차원 레이아웃
- Grid: 가로·세로 2차원 배치에 강한 2차원 레이아웃
실무에서는 둘을 함께 씁니다. Grid로 전체 페이지 구조를 잡고,
Flexbox로 각 컴포넌트 내부를 정렬하는 패턴이 가장 일반적입니다.
| 비교 항목 | Flexbox | Grid |
|---|---|---|
| 차원 | 1차원(row 또는 column) | 2차원(row + column) |
| 콘텐츠 우선 | 콘텐츠 크기 기준 | 컨테이너 크기 기준 |
| 명시적 트랙 | 없음 | grid-template-rows/columns |
| 항목 위치 | 순서대로 | 자유롭게 배치 가능 |
| 권장 용도 | 네비게이션·버튼 그룹·카드 내부 | 페이지 전체·갤러리·대시보드 |
Flexbox 핵심 개념#
.container {
display: flex;
flex-direction: row; /* 기본값: 가로 방향 */
justify-content: center; /* 주축 정렬 */
align-items: center; /* 교차축 정렬 */
gap: 16px; /* 자식 요소 간격 */
}
주축(Main axis)과 교차축(Cross axis)#
flex-direction이 row면 주축은 가로, 교차축은 세로입니다. column이면 반대.
flex-direction: row → 주축 = 가로(좌→우)
교차축 = 세로(상→하)
flex-direction: column → 주축 = 세로
교차축 = 가로
justify-content 값별 동작#
| 값 | 결과 |
|---|---|
flex-start | 시작 정렬(기본값) |
flex-end | 끝 정렬 |
center | 가운데 정렬 |
space-between | 양 끝에 붙이고 사이 균등 분배 |
space-around | 각 요소 양옆에 균등 여백 |
space-evenly | 모든 간격 동일 |
align-items 값별 동작#
| 값 | 결과 |
|---|---|
stretch | 교차축 전체 채움(기본값) |
flex-start | 교차축 시작 |
flex-end | 교차축 끝 |
center | 교차축 가운데 |
baseline | 텍스트 베이스라인 정렬 |
Flexbox가 적합한 경우#
- 네비게이션 바(아이템들을 한 줄에 배치)
- 버튼 그룹(아이콘 + 텍스트 정렬)
- 카드 내부 레이아웃
- 수직·수평 중앙 정렬
- 아이템 수가 동적으로 변하는 리스트
/* 수직·수평 완벽 중앙 정렬 — 가장 깔끔한 방법 */
.center {
display: flex;
justify-content: center;
align-items: center;
}
flex 단축 속성#
자식 요소의 크기 제어:
.item {
flex: 1 1 0;
/* flex-grow: 1 (남은 공간 분배) */
/* flex-shrink: 1 (부족하면 줄이기) */
/* flex-basis: 0 (기본 크기) */
}
.fixed {
flex: 0 0 200px; /* 200px 고정, 늘어나거나 줄지 않음 */
}
CSS Grid 핵심 개념#
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3열 균등 분배 */
grid-template-rows: auto;
gap: 24px;
}
fr 단위란?#
fr(fractional unit)은 남은 공간을 비율로 나누는 단위입니다.
grid-template-columns: 1fr 2fr 1fr;
/* 전체를 4등분 → 왼쪽 1/4, 가운데 2/4, 오른쪽 1/4 */
반응형 Grid 패턴: auto-fit vs auto-fill#
화면 크기에 맞춰 자동으로 열 수 조정:
/* auto-fill: 가능한 만큼 열 자리를 만듦(빈 자리 유지) */
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
/* auto-fit: 빈 자리를 채워 늘림(아이템이 큰 폭으로 늘어남) */
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
이 한 줄로 카드 그리드가 화면 크기에 따라 자동으로 1열, 2열, 3열로 바뀝니다. 미디어 쿼리 없이 반응형 완성.
| 차이 | auto-fill | auto-fit |
|---|---|---|
| 빈 자리 | 유지(여백 발생) | 채워서 늘림 |
| 권장 | 일반 그리드 | 항상 최대 너비 활용 |
Grid가 적합한 경우#
- 카드 갤러리, 상품 목록
- 신문 스타일 레이아웃(제목 + 본문 + 사이드바)
- 대시보드(다양한 크기의 위젯 배치)
- 헤더 + 사이드바 + 본문 + 푸터 페이지 구조
- 폼(label + input 정렬)
/* 사이드바 + 본문 + 광고 3열 레이아웃 */
.page {
display: grid;
grid-template-columns: 240px 1fr 300px;
gap: 32px;
}
grid-template-areas: 가독성 좋은 방법#
.layout {
display: grid;
grid-template-columns: 240px 1fr 300px;
grid-template-rows: 80px 1fr 60px;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
}
.header { grid-area: header; }
.nav { grid-area: nav; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
이 방식은 디자이너가 그린 와이어프레임을 그대로 코드로 옮길 수 있어 직관적입니다.
CSS subgrid: 중첩 그리드 정렬#
자식 요소가 부모 그리드의 트랙을 그대로 사용하는 기능입니다
(2023년부터 모든 주요 브라우저 지원).
.parent {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.child {
display: grid;
grid-template-columns: subgrid; /* 부모의 3열 그대로 사용 */
}
카드 그리드에서 모든 카드의 제목·이미지·버튼이 같은 라인에 정렬되어야 할 때 유용합니다.
Container Queries: 반응형의 새 차원#
미디어 쿼리는 화면 크기 기준이지만,
Container Query는 부모 컨테이너 크기 기준입니다(2023년부터 모든 주요 브라우저 지원).
.card-container {
container-type: inline-size;
container-name: card;
}
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
}
}
같은 카드 컴포넌트가 사이드바 안에서는 세로로, 메인 영역에서는 가로로 자동 배치됩니다. 컴포넌트 단위 반응형 디자인이 가능해졌습니다.
자주 쓰는 패턴 레시피#
1. 헤더: 로고 + 네비 + 버튼#
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 24px;
}
2. 카드 그리드(반응형)#
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
}
3. 전체 페이지 구조: Sticky Footer#
body {
display: grid;
grid-template-rows: auto 1fr auto; /* 헤더 / 본문(남은 공간) / 푸터 */
min-height: 100vh;
}
4. 아이콘 + 텍스트 인라인 정렬#
.icon-text {
display: flex;
align-items: center;
gap: 8px;
}
5. 폼 정렬(2열 그리드)#
.form {
display: grid;
grid-template-columns: auto 1fr;
gap: 12px 16px; /* 행 간격 12px, 열 간격 16px */
align-items: center;
}
6. 갤러리(Pinterest 스타일·masonry)#
CSS grid-template-rows: masonry(2024년 실험적 기능, 점진적 도입 중) 또는 JavaScript 라이브러리(Masonry, Isotope) 사용.
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-rows: 200px;
gap: 12px;
}
.tall { grid-row: span 2; }
.wide { grid-column: span 2; }
7. Holy Grail 레이아웃#
전통적인 헤더-사이드바-본문-푸터 패턴:
.page {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: 60px 1fr 60px;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
min-height: 100vh;
}
Tailwind CSS 대응표#
Tailwind를 사용한다면 유틸리티 클래스로 바로 적용할 수 있습니다.
| CSS | Tailwind |
|---|---|
display: flex | flex |
justify-content: center | justify-center |
align-items: center | items-center |
gap: 16px | gap-4 |
display: grid | grid |
grid-template-columns: repeat(3, 1fr) | grid-cols-3 |
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)) | grid-cols-[repeat(auto-fill,minmax(250px,1fr))] |
flex-direction: column | flex-col |
flex-wrap: wrap | flex-wrap |
flex: 1 1 0 | flex-1 |
성능 고려사항#
레이아웃 비용#
- Flexbox와 Grid는 모두 GPU 가속을 받지 않습니다(레이아웃은 CPU)
- 자주 변경되는 애니메이션은
transform사용(GPU) will-change남용 금지(메모리 사용)
큰 그리드 성능#
/* 1만 개 아이템 그리드는 가상 스크롤(Virtual Scroll) 권장 */
/* 그리드 자체보다 DOM 노드 수가 성능 병목 */
리액트에서는 react-window, react-virtualized 같은 라이브러리로 가상 스크롤 구현.
자주 묻는 질문#
Q. Flexbox만 써도 되지 않나요? Grid를 굳이 배워야 하나요?
A. 간단한 1차원 정렬은 Flexbox로 충분합니다. 하지만 복잡한 2차원 레이아웃, 불규칙한 크기의 그리드는 Grid가 훨씬 간결합니다. 둘 다 알아두면 상황에 맞게 선택할 수 있습니다.
Q. Internet Explorer도 지원해야 하나요?
A. IE는 2022년 6월 서비스 종료됐습니다. 현재 Flexbox와 Grid는 모든 주요 브라우저에서 완벽히 지원됩니다.
Q. gap과 margin의 차이는?
A. gap은 그리드·플렉스 컨테이너 내부 자식들 사이에만 적용됩니다. 첫 번째와 마지막 요소 바깥에는 여백이 생기지 않아 깔끔합니다. margin은 모든 방향에 적용되어 끝 요소에도 여백이 생깁니다.
Q. 동적인 콘텐츠가 있는 카드 높이를 맞추려면?
A. Grid 컨테이너의 자식들은 자동으로 같은 행에서 같은 높이가 됩니다. Flexbox는 align-items: stretch(기본값)로 같은 효과 가능.
Q. subgrid는 언제 쓰나요?
A. 카드 컴포넌트 내부의 제목·본문·버튼이 다른 카드들과 같은 라인에 정렬되어야 할 때 가장 유용합니다.
Q. Container Query와 미디어 쿼리 중 무엇을 써야 하나요?
A. 페이지 전체 레이아웃은 미디어 쿼리(뷰포트 기준),
컴포넌트 단위 반응형은 Container Query 사용. 같은 카드가 사이드바 안과 메인 영역에서 다르게 보여야 한다면
Container Query가 답입니다.
Q. CSS 그리드와 테이블 차이는?
A. <table>은 표 데이터를 위한 시맨틱 태그입니다. 레이아웃 용도로 <table>을 쓰는 것은 접근성·시맨틱 측면에서 안티패턴. CSS Grid가 정답입니다.
CSS 레이아웃 도구 활용#
CSS 레이아웃 도구에서 Flexbox·Grid 모드 선택,
열 수·간격·정렬 방향을 클릭으로 설정하면 CSS 코드가 자동 생성됩니다.
디자인 작업이 더 필요하다면 색상 팔레트 가이드, 그라디언트 가이드, 색상 대비 접근성, 박스 쉐도우 가이드도 함께 참고하세요.