본문으로 건너뛰기
Previous
Next
CSS Grid | 그리드 레이아웃 완벽 가이드

CSS Grid | 그리드 레이아웃 완벽 가이드

CSS Grid | 그리드 레이아웃 완벽 가이드

이 글의 핵심

CSS Grid: 그리드 레이아웃 Grid 기본 개념·Grid Template Columns/Rows.

HTML/CSS 시리즈 #06 · CSS Grid

솔직히 말하면, 페이지 뼈대·대시보드·갤러리는 Grid가 답이야. Flexbox? 한 줄(가로 또는 세로) 흐름엔 잘 맞는데, 1차원이라 “몇 열·몇 행”을 동시에 잡는 건 늘 애매해진다. Grid는 2차원—행(row) + 열(column)을 한 번에 설계하는 도구다. (너희 팀이 “플렉스로만” 하다 퍼센트·마이너스 마진 지옥 본 경험 있지?)


Grid 디버깅으로 하루…

어느 날 대시보드 grid-template-areas 짠 다음, 뷰포트 줄였더니 sidebar가 갑자기 맨 밑에 가 있는 거야. “내가 areas 잘못 썼나?” 싶어서 DevTools Layout → Grid 켰더니, 열·행 라인 번호가 눈에 박힌다. grid-column: 1 / -1진짜 어디를 가리키는지, span이 자동 배치랑 충돌한 건 아닌지, 한 줄씩 뜯으면서 맞췄지. min-width: 0 안 준 카드가 셀을 밀어서 fr이 이상해 보였던 것도, 그날 grid 오버레이 켜고 처음 알았다. 하루 쓴 거 같지만, 그때부터 “일단 grid 켜고 선부터 본다”가 습관이 됐어.


구식 float + clearfix 대신, 의도는 이렇게 쓰는 쪽이 낫다.

/* 레거시 */
.col-4 { float: left; width: 33.33%; }
/* 의도가 바로 읽힘 */
.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

2차원 잡는다 = 명시적 트랙·gap·(필요하면) areas. Flex로만 역할 바꿔 쓰다 보면 “한 줄” 사고에 갇힌다. Grid가 답, Flexbox는 1차원—이 조합(바깥 Grid, 안 Flex) 머리에 박아 두면 편하다.


언제 뭘 쓸지 (표 말고 그림)

Flex에 잘 맞는 것:  [툴바 ············ 버튼들 →→→  ]
                    (한 축, 한 줄 흐름)

Grid에 잘 맞는 것:  ┌────┬────┬────┐
                    │ H  │ H  │ H  │  ← 행+열 동시
                    ├────┼────┼────┤
                    │ S  │ M  │ M  │
                    └────┴────┴────┘
  • 네비·툴바·버튼 한 줄 → Flex
  • 헤더/사이드/메인 뼈대, 대시보드 → Grid
  • 한 칸이 여러 열·행 먹어야 하면 → Grid (span, grid-area, 라인)

조합: 바깥은 Grid, 카드 안쪽 정렬은 Flex. 레이어 나누면 CSS 읽기 쉬워진다.


컨테이너: display: grid, grid-template-*

display: grid직접 자식이 그리드 아이템. 용어는 ASCII로 보면 빠름.

      1     2     3     4   ← 열 라인
   1  ┌─────┬─────┬─────┐
      │  1  │  2  │  3  │
   2  ├─────┼─────┼─────┤
      │  4  │  5  │  6  │
   3  └─────┴─────┴─────┘
   ↑ 행 라인
  • 3열 = 열 라인 4개 — “전체 너비”는 grid-column: 1 / -1 같은 식
  • min-width: auto 때문에 안 줄어드는 자식이 있으면, 실무에선 min-width: 0 같이 같이 쓰는 경우 많다
.container {
  display: grid;
  grid-template-columns: 200px 200px 200px;
  grid-template-rows: 100px 100px;
  gap: 20px;
}

grid-template-areas — 말로는 “ASCII 덩어리”

.app {
  display: grid;
  grid-template-columns: 200px 1fr 1fr;
  grid-template-rows: 80px 1fr 1fr 60px;
  grid-template-areas:
    "header header header"
    "sidebar main main"
    "sidebar main main"
    "footer footer footer";
  min-height: 100vh;
  gap: 10px;
}
.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.footer  { grid-area: footer; }

같은 이름 셀은 직사각형이어야 한다—꼬이면 areas가 통째로 invalid.


라인·fr·gap·repeat·minmax·auto-fit

라인 번호 grid-column: 1 / 4 = 1번~4번 라인 사이 = 3칸. -1은 마지막 라인.

gap트랙 사이만. fr은 고정+gap남는 공간 비율—퍼센트+갭이랑 싸울 때 fr이 덜 꼬이는 경우가 많다.

.page {
  display: grid;
  grid-template-columns: 200px 1fr 2fr;
}

반응형 한 방은 흔히 이거:

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 20px;
}

auto-fill빈 열 슬롯이 남을 수 있고, auto-fit빈 열을 접어서 남는 칸이 늘어난다. “카드 꽉 채우기”는 보통 auto-fit부터 써 본다.

auto-fill:  [1][2][3][ ][ ]   … 빈 트랙 남을 수 있음
auto-fit:   [  1  ][  2  ][  3  ]  … 접힘, 셀 확장

아이템: span, place-self, 정렬

.card-wide {
  grid-column: 1 / 3;
  grid-row: 1 / 2;
}
.feature {
  grid-column: span 2;
}
  • place-items: 셀 정렬(컨테이너)
  • place-content: 그리드 덩어리 전체가 작을 때 남는 여백(컨테이너에 높이/고정 트랙 있을 때)

grid-auto-flow: dense는 빈칸 메울 수 있지만 시각 순서 vs 포커스 순서 괴리 날 수 있어서, 폼·리스트는 신중히.


실전: 대시보드 뼈대만

<div class="dashboard">
  <header class="dashboard__header">헤더</header>
  <aside class="dashboard__side">사이드</aside>
  <div class="dashboard__stats">…KPI 3칸…</div>
  <section class="dashboard__chart">차트</section>
</div>
.dashboard {
  min-height: 100vh;
  display: grid;
  gap: 20px;
  padding: 20px;
  grid-template-columns: 240px 1fr 1fr;
  grid-template-rows: 72px 140px 1fr;
  grid-template-areas:
    "head head  head"
    "side stat  stat"
    "side chart chart";
}
.dashboard__header { grid-area: head; }
.dashboard__side   { grid-area: side; }
.dashboard__stats  { grid-area: stat; display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.dashboard__chart  { grid-area: chart; }

좁아지면 @media에서 grid-template-areas만 세로로 갈아끼우면 된다. Holy Grail·갤러리 span 트릭·카드 auto-fit같은 원리라 여기서 굳이 길게 안 늘렸다. 더 필요하면 시리즈 다른 글·심화 글 봐.


Grid + Flex (이건 진짜 자주 씀)

.page { display: grid; grid-template-columns: 220px 1fr; }
.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

뼈대 2D = Grid, 한 줄·한 축 = Flex — 고집할 주제가 아니다. 다만 “전체를 Flex만으로 2D 흉내” 내는 쪽이 더 빨리 지저분해지는 경향은 있다. Grid가 답인 자리는 Grid 쓰자.


브라우저·트러블 (한 덩어리로)

모던 브라우저는 Grid Level 1 잘 쓴다. IE11 레거시면 -ms-·폴리필 이야기가 따로—2026 신규면 보통 대상 밖. subgrid는 Can I use 보고.

자주 터지는 것들을 표 대신:

  • 넘침min-width: 0 / overflow / word-break
  • fr 이상 → 콘텐츠가 트랙 최소를 밀어 올림 — minmax(0, 1fr) 등 상황마다
  • areas 깨짐 → 같은 이름이 직사각형 아님 — ASCII 다시 그려
  • align-content 안 먹음 → 행 합이 이미 뷰포트 꽉 참 — min-height/height·행 정의 점검

DevTools → Layout → Grid 오버레이는 필수다. Grid 디버깅으로 하루 쓴 사람은 다 동의함.


display: grid 기본 3×2 느낌 예시

<div class="grid">
  <div class="item i1">1</div>
  <div class="item i2">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
</div>
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(2, 100px);
  gap: 10px;
}
.i1 { grid-column: 1 / 3; }
.i2 { grid-column: 3 / 5; grid-row: 1 / 3; }

정리

  • Grid = 2D, Flex = 1D — 페이지 격자는 Grid 먼저 생각.
  • grid-template-*, gap, fr / minmax / auto-fit, areas, span, 1 / -1.
  • min-width: 0, areas 직사각형, dense+접근성은 머리에 두기.
  • 반말로 말하자면: 막힐 땐 DevTools grid 선 켜. 그게 젤 빠름.

속성 위치만 빠르게: 컨테이너 쪽은 template, gap, place-items / place-content, grid-auto-* — 아이템은 grid-column·row·grid-area, place-self. 표로 안 깔고, 위에서 이미 썼다.

다음에 읽을 글

관련 글

같이 보면 좋은 내부 글(심화·교차)

키워드: CSS, Grid, 레이아웃, 그리드, grid-template-areas, fr, minmax, auto-fit


자주 묻는 질문 (보충)

Q. justify-itemsjustify-content의 차이는?
A. …-items각 셀 안의 아이템, …-content트랙 전체가 작을 때 남는 여백.

Q. gridinline-grid는?
A. inline-grid는 인라인 흐름에 격자 끼워 넣을 때. 기본은 grid 쪽이 많다.

Q. Grid만으로 모든 걸?
A. 아니다. 1차원 정렬·툴바는 Flex가 단순한 경우 많다. 대신 “2D를 Flex로만” 억지로 만들지 말자.

배포 전엔 커밋·푸시 후 npm run deploy 같은 프로젝트 스크립트 쓰는 게 안전하다.