CSS Flexbox와 Grid, 무엇이 다르고 언제 선택해야 할까
빠른 답
- 한 줄 정렬, 버튼 그룹, 메뉴 바처럼 콘텐츠 흐름이 먼저 보이는 화면은 Flexbox 쪽이 더 단순하게 풀리는 경우가 많습니다.
- 페이지 골격, 카드 목록, 대시보드처럼 행과 열 규칙을 먼저 정해야 하는 화면은 Grid가 더 읽기 쉽고 배치도 안정적으로 유지됩니다.
- 둘은 대체재라기보다 함께 쓰는 경우가 많습니다. 바깥 구조는 Grid로, 카드나 헤더 내부 정렬은 Flexbox로 나누면 역할이 또렷해집니다.
1차원과2차원이라는 구분만 외우기보다, 콘텐츠 크기 변화가 먼저인지 배치 규칙이 먼저인지로 보면 선택이 한결 쉬워집니다.
Flexbox와 Grid는 둘 다 CSS 레이아웃 도구이지만, 브라우저가 레이아웃을 계산하는 출발점이 다릅니다. 브라우저는 DOM과 CSSOM을 합쳐 렌더 트리를 만든 뒤 레이아웃 단계에서 박스의 크기와 위치를 정하는데, 이때 Flexbox는 아이템 흐름을 중심에 두고, Grid는 트랙 구조를 중심에 둡니다.
목차
한눈에 비교
시간 흐름으로 이해하기
브라우저 안에서 실제로 무슨 순서로 일어날까
- HTML 파싱
- DOM 생성
- CSSOM 생성
- 렌더 트리 구성
- 레이아웃 계산
- 페인트와 컴포지팅
이 순서는 MDN의 Critical Rendering Path에서 설명하는 브라우저 렌더링의 기본 흐름과 맞닿아 있습니다. Flexbox와 Grid의 차이도 이 가운데 레이아웃 계산 단계에서 가장 선명하게 드러납니다.
Flexbox는 아이템이 어느 방향으로 흐르는지, 기본 크기가 얼마인지, 남는 공간을 누가 가져갈지를 계산합니다. 반대로 Grid는 컨테이너의 행과 열 트랙을 먼저 정하고, 각 아이템이 어느 셀이나 영역에 들어갈지를 계산합니다. 같은 화면이라도 어떤 모델을 쓰느냐에 따라 브라우저가 다시 계산해야 하는 범위와 읽기 방식이 달라집니다.
왜 둘 다 정렬 도구처럼 보여 헷갈릴까
두 도구 모두 justify-content, align-items, gap 같은 속성을 공유합니다. 이 공통점은 MDN의 flexbox와 다른 레이아웃 방식의 관계 문서에서 설명하듯 CSS Box Alignment 계열 개념을 함께 쓰기 때문입니다.
다만 정렬 속성이 비슷하다고 계산 모델까지 같지는 않습니다. Flexbox는 “이 아이템들이 이 방향으로 어떻게 흐를까”에 가까운 도구이고, Grid는 “이 화면을 어떤 칸 구조로 나눌까”에 가까운 도구입니다. 둘 다 요소를 가지런히 놓아주지만, 하나는 콘텐츠에서 시작하고 다른 하나는 배치 구조에서 시작합니다.
선택 기준 매트릭스
Flexbox가 먼저 떠오르는 장면
툴바, 필터 바, 메뉴, 배지 목록처럼 한 줄의 흐름이 중심인 UI는 Flexbox가 편하게 느껴집니다. 요소 수가 달라져도 주 축 기준으로 남는 공간을 다시 나누기 때문에, 레이아웃 의도가 비교적 그대로 유지됩니다.
.toolbar {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: center;
}
.toolbar .search {
flex: 1 1 240px;
min-width: 0;
}
.toolbar .actions {
display: flex;
gap: 8px;
margin-inline-start: auto;
}
이 패턴은 검색창 폭이 유동적이고 버튼 개수도 달라질 수 있는 화면에 잘 맞습니다. 다만 flex-wrap으로 여러 줄이 되면 각 줄이 독립적으로 계산된다는 점은 기억해 둘 만합니다. 카드 목록처럼 열 정렬의 일관성이 중요한 화면에서는 이 특성이 오히려 어색하게 보일 수 있습니다.
Grid가 먼저 떠오르는 장면
카드 목록, 대시보드, 갤러리처럼 “어느 칸에 무엇을 놓을지”를 먼저 정하는 화면은 Grid가 더 직접적인 표현을 제공합니다. 콘텐츠 길이가 조금씩 달라도 열 구조를 유지하기 쉬워서 화면 리듬이 무너지지 않는 편입니다.
.card-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 24px;
}
.card {
min-width: 0;
}
.card.featured {
grid-column: span 2;
}
repeat(auto-fit, minmax(240px, 1fr))는 “카드는 최소 240px을 확보하고, 남는 공간은 균등하게 분배한다”는 규칙을 먼저 세웁니다. 이런 선언은 반복되는 카드 UI나 대시보드 위젯처럼 구조 일관성이 중요한 화면에서 읽기 쉽습니다. MDN의 Grid 문서도 이런 트랙 중심 사고방식을 Grid의 강점으로 다룹니다.
함께 쓰는 구성이 더 자연스러운 경우
많은 화면은 둘 중 하나로만 끝나지 않습니다. 페이지 전체 구조는 Grid로 나누고, 각 영역 내부의 제목 정렬이나 버튼 묶음은 Flexbox로 처리하면 역할이 자연스럽게 분리됩니다.
.app {
display: grid;
grid-template-columns: 280px minmax(0, 1fr);
min-height: 100vh;
}
.main {
display: grid;
grid-template-rows: auto 1fr;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 12px;
}
여기서 minmax(0, 1fr)는 긴 텍스트나 넓은 콘텐츠 때문에 트랙이 예상보다 커지며 넘치는 상황을 줄이는 데 도움이 됩니다. 바깥은 칸 구조, 안쪽은 콘텐츠 흐름이라는 식으로 책임을 나누면 CSS를 읽거나 수정할 때도 맥락이 분명해집니다.
DevTools로 확인하는 포인트
레이아웃 문제가 생기면 문법만 보지 말고 브라우저가 무엇을 다시 계산했는지 확인하는 편이 좋습니다. Chrome DevTools에서는 Flexbox와 Grid 모두 오버레이를 켜서 정렬 축, 라인, 트랙 크기를 시각적으로 볼 수 있습니다. 관련 기능은 Flexbox 디버깅 문서와 Grid 디버깅 문서에서 확인할 수 있습니다.
성능 패널에서는 어떤 상호작용이 Layout과 Paint를 얼마나 일으켰는지 볼 수 있습니다. 같은 사이드 패널 토글이라도 width를 바꾸는 방식은 레이아웃 계산을 다시 요구하기 쉽고, transform 중심 전환은 경우에 따라 컴포지팅 단계에서 더 가볍게 처리됩니다. 또 Rendering 패널의 Paint flashing, Layout Shift Regions, Layer Borders를 켜 보면 화면 어디가 다시 칠해졌는지와 레이어 분리가 어떻게 되었는지 더 분명하게 보입니다. 자세한 항목은 Chrome DevTools의 rendering 성능 가이드에서 다룹니다.
상호작용에 따른 레이아웃 변화를 직접 측정해 보고 싶다면, 아래처럼 클래스 토글 전후에 performance.mark()와 requestAnimationFrame()을 붙여 간단히 시간을 기록할 수 있습니다.
const toggle = document.querySelector('.toggle');
const sidebar = document.querySelector('.sidebar');
toggle.addEventListener('click', () => {
performance.mark('toggle-start');
sidebar.classList.toggle('is-collapsed');
requestAnimationFrame(() => {
sidebar.getBoundingClientRect();
performance.mark('toggle-end');
performance.measure('sidebar-layout', 'toggle-start', 'toggle-end');
console.table(performance.getEntriesByName('sidebar-layout').slice(-1));
});
});
이 코드는 DevTools의 Performance 기록을 대신하지는 않지만, 어떤 상호작용이 레이아웃 읽기와 맞물리는지 빠르게 확인하는 데는 도움이 됩니다. Flexbox와 Grid 자체보다도, 그 레이아웃을 어떤 속성으로 계속 흔들고 있는지가 체감 비용에 더 큰 영향을 주는 경우도 적지 않습니다.
자주 헷갈리는 지점
flex-wrap이 있으니 Grid가 필요 없다고 보기는 어렵습니다. Flexbox의 각 줄은 독립적으로 계산되므로, 여러 줄 카드 목록에서 열 폭이 일정하게 유지되지는 않습니다.- Grid가 항상 더 무겁다고 보기도 어렵습니다. 실제 비용은 DOM 크기, 변경 범위, 애니메이션 속성, 페인트 영역에 더 크게 좌우됩니다.
justify-content와align-items를 둘 다 쓴다고 해서 같은 레이아웃 모델로 보면 설명이 자주 꼬입니다. 정렬 속성은 비슷해도 크기와 위치를 계산하는 출발점은 다릅니다.- “한 줄이면 Flexbox, 여러 줄이면 Grid”처럼 외우는 방식도 자주 빗나갑니다. 여러 줄이어도 흐름 중심이면 Flexbox가 맞을 수 있고, 한 화면이어도 구조 중심이면 Grid가 더 잘 맞을 수 있습니다.
더 읽을 거리
- MDN: Critical Rendering Path
- MDN: Basic concepts of flexbox
- MDN: CSS grid layout
- MDN: Relationship of flexbox to other layout methods
- Chrome DevTools: Inspect and debug CSS flexbox layouts
- Chrome DevTools: Inspect CSS grid layouts
원문 참고
https://www.maeil-mail.kr/question/51
댓글
댓글 쓰기