반응형
안녕하세요 😊
이번 포스팅에서는 CSS Grid와 Flexbox를 “어떤 상황에서 무엇을 써야 하는지” 관점에서 깊게 풀어보겠습니다.
두 기술은 모두 강력한 레이아웃 시스템이지만 목적이 다릅니다.
초보자 분들도 헷갈리지 않도록,
개념 → 속성 → 실전 패턴 → 선택 체크리스트 → 자주 하는 실수 순서로 차근차근 정리 해보겠습니다.
1) 핵심 요약이 아니라 “핵심 이해”: Grid는 2차원, Flex는 1차원
- Flexbox는 1차원(행 또는 열 한 방향) 정렬에 특화되어 있습니다.
버튼 그룹, 네비게이션 바, 카드 내부 정렬처럼 한 줄 안에서의 배치·정렬·간격 제어에 특히 강합니다. - Grid는 2차원(행 + 열 동시) 레이아웃에 적합합니다.
페이지 전체 레이아웃, 대시보드, 잡지형 배치처럼 행과 열을 동시에 설계해야 할 때 강력합니다.
한 줄 정렬·정돈 = Flex, 페이지 뼈대·격자 = Grid
이 관점만 먼저 정확히 기억하시면 이후 선택이 쉬워집니다.
2) Flexbox: 1차원 레이아웃의 만능 드라이버
2-1. 컨테이너 vs 아이템(속성 분리 이해)
.container {
display: flex; /* Flex 컨테이너 선언 */
flex-direction: row; /* 행(row) 기준 배치(기본값) */
justify-content: space-between; /* 가로(주축) 정렬 */
align-items: center; /* 세로(교차축) 정렬 */
gap: 12px; /* 아이템 간 간격 */
}
.item {
flex: 0 0 auto; /* flex-grow flex-shrink flex-basis */
}
- 컨테이너 속성: display:flex, flex-direction, flex-wrap, justify-content, align-items, gap 등
- 아이템 속성: flex, flex-grow, flex-shrink, flex-basis, align-self, order 등
2-2. 축 이해(주축/교차축)
- flex-direction: row이면 가로가 주축, 세로가 교차축입니다.
- flex-direction: column이면 세로가 주축, 가로가 교차축입니다.
이 관점을 알면 justify-*(주축 정렬) vs align-*(교차축 정렬)의 차이가 명확해집니다.
2-3. 실전 패턴 ①: 네비게이션 바
<nav class="nav">
<div class="logo">Brand</div>
<ul class="menu">
<li>Docs</li><li>Blog</li><li>Pricing</li>
</ul>
<button class="cta">Sign in</button>
</nav>
.nav { display:flex; align-items:center; justify-content:space-between; padding:12px 16px; }
.menu { display:flex; gap:16px; list-style:none; margin:0; padding:0; }
- 특징: 수평 정렬 + 간격 + 가운데 맞춤을 한 번에 해결.
반응형에서는 .menu를 wrap 시키거나, 작은 화면에서 햄버거 메뉴로 교체합니다.
2-4. 실전 패턴 ②: 미디어 오브젝트(아바타 + 텍스트)
<div class="media">
<img src="avatar.jpg" alt="" class="avatar">
<div class="body">
<h4>제목</h4>
<p>설명 텍스트…</p>
</div>
</div>
.media { display:flex; gap:12px; align-items:flex-start; }
.avatar { width:48px; height:48px; border-radius:50%; flex:0 0 48px; }
.body { flex:1 1 auto; min-width:0; } /* 긴 텍스트 줄바꿈 대비 */
- 팁: 긴 텍스트가 있는 영역에는 min-width:0을 줘야 overflow 없이 줄바꿈이 됩니다(자주 빠뜨리는 부분).
2-5. Flex에서 자주 하는 실수
- flex-basis와 width를 혼용해 레이아웃이 흔들리는 경우가 많습니다.
우선순위는 flex-basis가 높습니다. 고정 폭이 필요하면 flex: 0 0 200px; 같이 명시하세요. - 자식에 overflow 문제가 생기면 부모 또는 자식에 min-width: 0을 고려하세요.
Flex 컨텍스트에선 이 한 줄이 살리는 경우가 많습니다.
3) CSS Grid: 2차원 레이아웃의 청사진
3-1. 핵심 개념
- 트랙(track): 열(column)과 행(row)을 구성하는 선 사이의 공간
- 라인(line): 트랙을 구분하는 선(라인 번호/이름으로 위치 지정 가능)
- 셀(cell): 행×열이 만드는 격자 칸
- 명시적/암시적 그리드: grid-template-*로 만든 칸은 명시적, 자동 배치로 늘어나는 칸은 암시적
3-2. 기본 문법(가장 많이 쓰는 속성)
.grid {
display: grid;
grid-template-columns: repeat(12, 1fr); /* 12열 그리드 */
grid-template-rows: auto; /* 행 높이는 내용에 맞춤 */
gap: 12px; /* 행/열 간격 */
}
.item-a { grid-column: 1 / 4; } /* 1~3열 차지 */
.item-b { grid-column: 4 / 13; } /* 4~12열 차지 */
- fr 단위는 남은 공간 비례 분배입니다. 레이아웃 그릴 때 거의 표준처럼 사용합니다.
- repeat(), minmax(), auto-fit, auto-fill을 익히면 반응형이 매우 쉬워집니다.
3-3. 실전 패턴 ①: 반응형 카드 그리드(미디어쿼리 최소화)
.cards {
display:grid;
/* 가로 폭이 240px 미만으로 쪼개지지 않도록 최소폭 보장 */
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap:16px;
}
- 화면이 넓으면 칼럼 수가 늘고, 좁아지면 자동으로 줄어 미디어쿼리 없이도 깔끔한 반응형이 됩니다.
3-4. 실전 패턴 ②: 페이지 뼈대(헤더/사이드/본문/푸터)
.layout {
display:grid;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"aside main"
"footer footer";
min-height: 100dvh; /* 뷰포트 꽉 채우기 */
gap: 12px;
}
.header { grid-area: header; }
.aside { grid-area: aside; }
.main { grid-area: main; }
.footer { grid-area: footer; }
- 장점: 구조를 시각적으로 선언(grid-template-areas) → 협업 시 의사소통이 매우 쉬워집니다.
- 모바일에서는 한 줄 변경으로 1열 레이아웃 변환이 가능합니다.
@media (max-width: 768px) {
.layout {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"aside"
"footer";
}
}
3-5. 실전 패턴 ③: 정확한 중앙 정렬
.center {
display:grid;
place-items:center; /* align-items + justify-items 동시 설정 */
min-height: 300px;
}
- Flex로도 가운데 정렬이 가능하지만, 가로·세로 동시 중앙은 Grid의 place-items:center 한 줄이 가장 깔끔합니다.
3-6. Grid에서 자주 하는 실수
- 암시적 행 높이: 열만 정의하고 행을 정의하지 않으면, 예상과 다른 암시적 행이 만들어져 카드 높이가 들쭉날쭉할 수 있습니다. 필요 시 grid-auto-rows로 기본 높이(또는 minmax 전략)를 지정하세요.
- 라인 번호 의존: grid-area 이름을 사용하면 템플릿 변경이 쉬워집니다(라인 번호는 템플릿 변경 시 무너질 수 있음).
4) Grid vs Flex, 무엇을 선택할까? (의사결정 체크리스트)
아래 질문에 “예/아니오”로 답해 보시면 결정이 훨씬 쉬워집니다.
- 행과 열을 동시에 설계해야 하나요?
예 → Grid. 아니오 → 다음 질문. - 한 줄(혹은 한 열)에서 요소를 정렬·분배만 하면 되나요?
예 → Flex. - 요소의 시맨틱한 영역 이름(헤더/사이드/본문/푸터)이 중요한가요?
예 → Grid(areas). - 동일한 높이/정렬/간격으로 버튼·뱃지·아이템들을 일렬 배치하나요?
예 → Flex. - 카드가 화면 폭에 맞춰 ‘자동으로’ 열 개수가 늘었다 줄었다 해야 하나요?
예 → Grid + auto-fit/minmax. - **내부 콘텐츠 정렬(아바타 옆 텍스트, 태그 줄바꿈 등)**이 주 관심사인가요?
예 → Flex.
실무에서는 **“페이지 뼈대는 Grid, 내부 정렬은 Flex”**의 혼합 사용이 가장 많습니다.
5) 혼합 사용 레시피(현업에서 바로 쓰는 예)
레시피 A) 대시보드
- 바깥 뼈대: Grid(헤더/사이드/메인/푸터)
- 카드 목록: Grid(auto-fit + minmax)
- 카드 내부 정렬: Flex(아이콘+텍스트, 버튼 그룹)
레시피 B) 블로그 아티클 레이아웃
- 본문/TOC(목차) 2열: Grid(1fr / 280px)
- 목차 항목: Flex(아이콘 + 텍스트 정렬)
- 반응형: 768px 이하에서 Grid를 1열로 전환
레시피 C) 폼 UI
- 라벨/입력칸 2열 정렬: Grid(열 템플릿으로 정렬 균일화)
- 버튼 줄: Flex(우측 정렬 + 간격)
6) 반응형 전략: 미디어쿼리 없이도 우아하게
6-1. Grid의 auto-fit + minmax
.grid-auto {
display:grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
}
- 컬럼 “최소 220px, 최대 1fr”로 늘었다 줄었다 → 콘텐츠가 스스로 자리를 찾습니다.
6-2. Flex의 wrap + gap
.flex-wrap {
display:flex;
flex-wrap:wrap;
gap:12px;
}
.item { flex: 1 1 220px; } /* 최소 220px, 남으면 늘어나기 */
- Flex도 wrap과 flex-basis 조합으로 간단한 카드 그리드를 만들 수 있습니다.
- 다만, 열 정렬/줄맞춤은 Grid가 더 정확합니다.
7) 접근성·유지보수 관점에서 꼭 알아야 할 점
- 시각 순서와 DOM 순서
- Flex의 order나 Grid의 위치 지정으로 화면 순서를 바꾸더라도 DOM 순서는 변하지 않습니다.
- 키보드 포커스, 스크린리더는 DOM 순서를 따르므로, 시맨틱과 접근성을 고려해 논리적인 DOM 순서를 유지하시길 권장합니다.
- 네이밍(areas)과 협업
- Grid의 grid-template-areas는 디자이너·기획자와 협업할 때 강력한 커뮤니케이션 도구가 됩니다(“헤더/사이드/메인/푸터”가 코드에 드러남).
- 유틸리티화
- 자주 쓰는 패턴(센터링, 균등 간격, 카드グ리드)을 유틸 클래스로 만들어 두면 유지보수성이 크게 올라갑니다.
8) 자주 묻는 질문(FAQ)
Q1. 단순 2열/3열 카드, Flex로 해도 되나요?
A. 가능합니다. 다만 행 간 높이 맞춤, 간격 균등, 열 정렬이 중요하면 Grid가 더 깔끔합니다.
Q2. 카드 높이가 들쭉날쭉해요.
A. Grid면 grid-auto-rows나 내부 카드 레이아웃을 점검하세요. Flex면 자식에 min-width:0/min-height 조정, 이미지 비율(예: aspect-ratio) 고정이 필요할 수 있습니다.
Q3. 중앙 정렬은 무엇이 더 쉬운가요?
A. Grid의 place-items:center가 가장 간결합니다. Flex는 justify-content:center + align-items:center 두 줄이 필요합니다.
9) 실전 스니펫 모음(복붙용)
(1) 완전 중앙 정렬(가로+세로)
.center {
display:grid;
place-items:center;
min-height: 60vh;
}
(2) 반응형 카드 그리드(미디어쿼리 최소화)
.cards {
display:grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
(3) 버튼/태그 수평 나열 + 줄바꿈
.pills {
display:flex;
flex-wrap:wrap;
gap:8px;
}
.pills > .pill { padding:.4em .8em; border-radius:999px; background:#f2f2f2; }
(4) Holy Grail(헤더/푸터 + 좌측사이드 + 본문)
.holy {
display:grid; min-height:100dvh; gap:12px;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"aside main"
"footer footer";
}
.header{grid-area:header;} .aside{grid-area:aside;}
.main{grid-area:main;} .footer{grid-area:footer;}
@media (max-width: 768px){
.holy{
grid-template-columns: 1fr;
grid-template-areas:
"header" "main" "aside" "footer";
}
}
10) 마무리: 선택 기준 한 줄 정리(하지만 요약이 아닌 결론)
- 한 줄·한 방향 정렬, 요소 간 간격·정렬·순서 조절이 핵심이라면 Flex가 가장 빠르고 읽기 쉽습니다.
- 페이지 뼈대, 격자, 행·열 동시 설계, 반응형 카드 자동 칼럼이 필요하다면 Grid가 정답입니다.
- 현업에서는 **Grid(바깥 구조) + Flex(내부 정렬)**의 혼합이 가장 실용적이며,
유지보수성과 접근성까지 고려한 논리적 DOM 순서를 항상 함께 챙기면 좋습니다.
반응형
'HTML, CSS' 카테고리의 다른 글
스크립트 없이 CSS만으로 반짝이는 글자 애니메이션 만들기 (0) | 2025.09.18 |
---|---|
<figure>와 <figcaption> – 이미지와 설명을 의미 있게 묶는 방법 (0) | 2025.09.16 |
스크립트 없이 CSS만으로 로딩 스피너 4종 만들기 – keyframes와 transform 완전 정복 (0) | 2025.09.11 |
<mark> 태그로 검색 하이라이트 구현하기 – 접근성과 SEO까지 챙기기 (0) | 2025.09.07 |
<time> 태그 – 날짜와 시간을 의미 있게 표현하는 방법 (0) | 2025.09.03 |