CSS

12컬럼 그리드 없이 반응형 레이아웃 — CSS Grid와 Flexbox 비교

Bootstrap의 12컬럼 시스템을 CSS Grid와 Flexbox만으로 대체하는 현대적 레이아웃 패턴을 비교한다.

9 min read
CSSGridFlexbox반응형레이아웃
12컬럼 그리드 없이 반응형 레이아웃 — CSS Grid와 Flexbox 비교

한 줄 결론

미디어 쿼리 없는 자동 반응형이 필요하면 Grid, 고아 컬럼을 반드시 없애야 하면 Flexbox.

Bootstrap의 12컬럼 그리드 시스템은 오랫동안 반응형 레이아웃의 표준이었다. col-md-4, col-lg-6 같은 클래스를 잔뜩 붙여야 했고, 심지어 HTML 구조까지 레이아웃에 맞춰야 했다.

CSS Grid와 Flexbox가 성숙한 지금, 유틸리티 클래스를 쓰지 않고도 1~4컬럼 반응형 레이아웃을 구현할 수 있다.


왜 12컬럼이 문제였나

12컬럼 시스템의 문제는 HTML이 레이아웃을 알아야 한다는 점이다.

index.html — 12컬럼 방식의 HTML 오염
<!-- 레이아웃 정보가 HTML 클래스로 노출됨 -->
<div class="row">
  <div class="col-12 col-md-6 col-lg-4">카드 1</div>
  <div class="col-12 col-md-6 col-lg-4">카드 2</div>
  <div class="col-12 col-md-6 col-lg-4">카드 3</div>
</div>

클래스가 많아질수록 HTML이 지저분해지고, 레이아웃을 바꾸려면 HTML을 건드려야 한다. CSS만 수정해서 레이아웃을 바꿀 수 없다.


핵심 비교표

특성CSS GridFlexbox
자동 반응형✅ 미디어 쿼리 없이 가능❌ 미디어 쿼리 필요
고아 컬럼 방지❌ 발생 가능✅ 방지 가능
서브컨테이너✅ 독립적으로 작동❌ 뷰포트 기반
2차원 제어✅ 행+열 동시❌ 1차원만
적합한 위치카드 그리드, 갤러리헤더, 내비게이션, 주 레이아웃

CSS Grid 방식

기본 패턴

styles/grid-layout.css — 자동 반응형 카드 그리드
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1.5rem;
}
index.html — 클래스 없이 깔끔한 HTML
<div class="card-grid">
  <div class="card">카드 1</div>
  <div class="card">카드 2</div>
  <div class="card">카드 3</div>
  <div class="card">카드 4</div>
</div>

이 두 줄로 미디어 쿼리 없는 반응형 그리드가 완성된다.

작동 원리

repeat(auto-fit, minmax(15rem, 1fr)) 를 풀면:

  1. minmax(15rem, 1fr) — 최소 너비는 15rem, 나머지 공간은 1fr로 균등 분배
  2. auto-fit — 컨테이너 너비에 맞게 컬럼 수를 자동으로 결정
  3. 컨테이너가 좁아지면 15rem 최소 너비를 지키기 위해 자동으로 다음 행으로 이동

비유하면 책상 위에 최소 가로 15cm 크기의 책을 최대한 많이 펼쳐놓는 것과 같다. 책상이 좁아지면 책이 자연스럽게 밑으로 내려간다.

[💡 잠깐! 이 용어는?] auto-fit vs auto-fill: auto-fit은 남는 공간을 기존 아이템에 분배해 늘린다. auto-fill은 빈 트랙을 만들어 남겨둔다. 카드 그리드처럼 아이템이 꽉 찬 경우에는 차이가 없다.

Grid의 한계: 고아 컬럼

4컬럼 그리드에 5개 아이템이 있으면:

[카드1] [카드2] [카드3] [카드4]
[카드5] [빈칸] [빈칸] [빈칸]  ← 고아 컬럼

카드5가 혼자 왼쪽에 달랑 남는다. 서비스 성격에 따라 이게 허용될 수도, 안 될 수도 있다.

가변 컬럼 수 고정

최소/최대 컬럼 수를 고정하고 싶다면:

styles/grid-clamped.css — 최소 2개, 최대 4개 컬럼
.card-grid {
  display: grid;
  /* 최소 2컬럼, 최대 4컬럼 */
  grid-template-columns: repeat(
    clamp(2, calc(100% / 250px), 4),
    1fr
  );
  gap: 1.5rem;
}

또는 미디어 쿼리로 명시적 제어:

styles/grid-responsive.css — 명시적 반응형 컬럼
.card-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}
 
@media (min-width: 640px) {
  .card-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
 
@media (min-width: 1024px) {
  .card-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

Flexbox 방식

기본 패턴

styles/flex-layout.css — 고아 컬럼 없는 Flexbox 그리드
.card-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}
 
.card-grid > * {
  flex: 1 1 calc(25% - 1.5rem); /* 4컬럼 기준 */
  min-width: 200px;
}
 
@media (max-width: 640px) {
  .card-grid > * {
    flex: 1 1 100%; /* 모바일: 1컬럼 */
  }
}
index.html — Flexbox 방식 HTML
<div class="card-grid">
  <div class="card">카드 1</div>
  <div class="card">카드 2</div>
  <div class="card">카드 3</div>
  <div class="card">카드 4</div>
  <div class="card">카드 5</div>
</div>

5번째 카드가 다음 행으로 내려오지만, flex: 1이 적용되어 행 전체를 채운다. 고아 컬럼이 사라진다.

고아 컬럼을 없애는 원리

flex: 1 1 calc(25% - 1.5rem):

  • 1 1 — 늘어나고(grow) 줄어들(shrink) 수 있음
  • calc(25% - 1.5rem) — 4컬럼의 기본 너비 (gap 제외)

마지막 행의 아이템이 적어도 flex-grow: 1이 빈 공간을 채우므로 혼자 남지 않고 늘어난다.

[💡 잠깐! 이 용어는?] 고아 컬럼(Orphan Column): 그리드의 마지막 행에 컬럼 수보다 적은 아이템이 있을 때, 왼쪽에 달랑 남는 아이템. 카드 갤러리에서 시각적으로 어색해 보일 수 있다.


선택 체크리스트

CSS Grid가 유리한 경우:

  • 미디어 쿼리 없이 자동 반응형이 필요하다
  • 서브컨테이너(컴포넌트 안의 그리드)에도 사용할 계획이다
  • 행과 열을 동시에 제어해야 한다
  • 고아 컬럼이 허용된다 (갤러리, 블로그 카드 등)

Flexbox가 유리한 경우:

  • 고아 컬럼을 반드시 없애야 한다
  • 주로 페이지 상단 레이아웃에만 사용한다
  • 아이템 수가 일정하지 않다
  • 한 방향(가로 또는 세로)으로만 제어하면 된다

실전 사용 패턴

대부분의 카드 그리드 → Grid

styles/blog-grid.css — 블로그 카드 그리드
.post-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 2rem;
}

헤더 / 내비게이션 → Flexbox

styles/header.css — 헤더 레이아웃
.site-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

두 가지를 조합

styles/page-layout.css — Grid + Flexbox 조합
/* 페이지 전체 레이아웃: Grid */
.page {
  display: grid;
  grid-template-columns: 1fr 300px;
  gap: 2rem;
}
 
/* 사이드바 내부 카드: Flexbox */
.sidebar-cards {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

마무리

12컬럼 그리드는 CSS가 부족하던 시절의 해결책이었다. 지금은 필요 없다.

  • 자동 반응형 카드 그리드 → grid-template-columns: repeat(auto-fit, minmax(...)) 한 줄
  • 고아 컬럼 없는 균등 레이아웃 → flex: 1 1 calc(25% - gap)
  • 두 방식을 용도에 맞게 조합하면 Bootstrap 없이 깔끔한 반응형을 만들 수 있다.

유틸리티 클래스가 없어도 된다. HTML을 레이아웃에 종속시키지 않아도 된다. CSS 두 줄이면 충분하다.


참고: