웹 레이아웃을 짤 때 Grid를 써야 하나 Flexbox를 써야 하나 고민한 적 있을까. 대부분의 개발자들은 둘 다 '정렬된 박스들'이라고 생각해서 그냥 익숙한 것만 쓰거나, 구글에서 답을 찾아서 복사-붙여넣기한다. 다만 두 방식은 근본적으로 다른 목적을 가지고 있고, 어떤 상황에서 어느 것을 쓰느냐에 따라 코드 복잡도와 유지보수성이 완전히 달라진다. 이번에는 Grid와 Flexbox의 정확한 차이를 이해하고, 실제 프로젝트에서 올바른 선택을 할 수 있도록 정리해보겠다.

 

1단계. Grid와 Flexbox의 근본적 차이 이해하기
Flexbox는 1차원(한 방향) 레이아웃을 위한 도구다. 컨테이너 안의 아이템들을 가로 줄로 늘어놓거나, 세로 열로 쌓을 수 있다. Flexbox는 아이템들이 차지하는 공간 안에서 얼마나 확장하거나 축소할지만 신경 쓴다. 예를 들어 네비게이션 바에서 버튼들을 균등하게 배치하려면 Flexbox가 최고다.

Grid는 2차원(두 방향) 레이아웃을 위한 도구다. 행과 열을 동시에 정의해서 마치 엑셀 스프레드시트처럼 칸을 만들고, 그 칸에 요소들을 배치한다. Grid는 전체 구조를 먼저 정의한 후 각 아이템이 어느 칸에 들어갈지 명확하게 지정한다. 예를 들어 웹사이트의 헤더, 사이드바, 메인 콘텐츠, 푸터를 한 번에 배치하는 레이아웃은 Grid가 훨씬 깔끔하다.

특성 Flexbox Grid
방향 1차원(가로 또는 세로) 2차원(가로 + 세로)
구조 정의 컨테이너만 정의, 아이템은 자동 배치 행과 열을 명시적으로 정의
콘텐츠 중심 아이템에 따라 크기 변함(Content-first) 레이아웃에 따라 아이템 배치(Layout-first)
복잡도 간단한 1줄 정렬에 최적 복잡한 다중 영역 레이아웃에 최적
예시 네비게이션, 버튼 그룹 대시보드, 웹사이트 전체 레이아웃

 

2단계. Flexbox 실전 사용법 - 1차원 정렬이 필요할 때
Flexbox는 아이템들을 한 줄에 배치하고 남은 공간을 어떻게 나눌지 정하는 방식이다. 컨테이너에만 display: flex를 선언하면 자식 요소들이 자동으로 정렬된다.

✗ 잘못된 예시(Flexbox 오남용)

<style>
.page-layout {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}
.header { width: 100%; }
.sidebar { width: 20%; }
.main { width: 60%; }
.footer { width: 100%; }
</style>

<div class="page-layout">
  <div class="header">헤더</div>
  <div class="sidebar">사이드바</div>
  <div class="main">메인</div>
  <div class="footer">푸터</div>
</div>

이 방식은 작동하지만 문제가 있다. Flexbox는 wrap을 쓸 때 자동으로 다음 줄로 넘어가는데, footer가 sidebar와 main 옆에 나타날 수 있다. 너비 백분율도 수동으로 계산해야 하고 반응형 대응이 까다롭다.

✓ 올바른 Flexbox 사용(1줄 정렬)

<style>
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 20px;
  background: #333;
}
.nav-item {
  color: white;
  cursor: pointer;
}
.nav-item:hover {
  opacity: 0.7;
}
</style>

<div class="navbar">
  <div>로고</div>
  <div class="nav-item">홈</div>
  <div class="nav-item">상품</div>
  <div class="nav-item">연락처</div>
</div>

이것이 Flexbox의 진정한 용도다. 한 줄에 여러 아이템을 배치하고, justify-content로 좌우 배치를 제어하며, align-items로 수직 정렬을 한다. 코드가 간결하고 반응형 대응도 쉽다.

 

3단계. Grid 실전 사용법 - 2차원 레이아웃이 필요할 때
Grid는 먼저 행과 열의 구조를 선언한 후, 각 아이템이 어느 영역을 차지할지 명시한다. 반응형 대응도 미디어 쿼리 하나로 깔끔하게 처리된다.

✓ Grid로 전체 페이지 레이아웃 구성

<style>
.page-layout {
  display: grid;
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: auto 1fr auto;
  gap: 20px;
  height: 100vh;
}
.header {
  grid-column: 1 / -1;
  background: #333;
  color: white;
  padding: 20px;
}
.sidebar {
  background: #f0f0f0;
  padding: 20px;
}
.main {
  background: white;
  padding: 20px;
}
.footer {
  grid-column: 1 / -1;
  background: #333;
  color: white;
  padding: 20px;
}

@media (max-width: 768px) {
  .page-layout {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto auto;
  }
  .header { grid-column: 1; }
  .sidebar { grid-column: 1; }
  .main { grid-column: 1; }
  .footer { grid-column: 1; }
}
</style>

<div class="page-layout">
  <div class="header">헤더</div>
  <div class="sidebar">사이드바</div>
  <div class="main">메인 콘텐츠</div>
  <div class="footer">푸터</div>
</div>

Grid는 레이아웃의 의도가 명확하다. grid-template-columns로 3개 열(200px, 1fr, 200px)을 정의하고, grid-template-rows로 3개 행을 정의했다. grid-column: 1 / -1은 첫 번째 열부터 마지막 열까지 span한다는 뜻이다. 반응형으로 변경할 때도 grid-template-columns만 바꾸면 된다.

✓ Grid로 상품 카드 그리드 구성

<style>
.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
  padding: 20px;
}
.product-card {
  background: white;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.product-card img {
  width: 100%;
  height: 200px;
  object-fit: cover;
}
.product-card p {
  padding: 10px;
}
</style>

<div class="product-grid">
  <div class="product-card">
    <img src="product1.jpg" alt="상품1" />
    <p>상품1</p>
  </div>
  <div class="product-card">
    <img src="product2.jpg" alt="상품2" />
    <p>상품2</p>
  </div>
  <div class="product-card">
    <img src="product3.jpg" alt="상품3" />
    <p>상품3</p>
  </div>
</div>

repeat(auto-fit, minmax(250px, 1fr))은 GridTemplate의 강력한 기능이다. 화면 크기에 맞춰 자동으로 열 개수를 조절하면서도, 최소 250px 너비를 유지한다. 미디어 쿼리 없이도 완벽한 반응형이 된다.

 

4단계. 주의사항 - Grid와 Flexbox를 언제 조합해야 하나

✗ 잘못된 중첩(Grid 안에 Flex 오남용)

<style>
.layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
.card {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
</style>

<div class="layout">
  <div class="card">
    <h3>제목</h3>
    <p>내용</p>
    <button>버튼</button>
  </div>
</div>

이것도 작동하지만 불필요하게 복잡하다. 카드 내부 요소들을 세로로 정렬하려면 Grid로도 충분하다.

✓ 올바른 중첩(Grid 안에 Flex 필요할 때)

<style>
.dashboard {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
.stat-box {
  background: white;
  padding: 20px;
  border-radius: 8px;
}
.stat-box-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}
</style>

<div class="dashboard">
  <div class="stat-box">
    <div class="stat-box-header">
      <span>매출</span>
      <span>↑ 12%</span>
    </div>
    <p>$1,234,567</p>
  </div>
</div>

이것이 올바른 조합이다. 대시보드 전체는 Grid(2열 레이아웃)로, 각 카드 내부의 헤더는 Flexbox(타이틀과 수치를 좌우 정렬)로 처리한다. 계층이 명확하고 각 도구가 자기 역할을 한다.

 

5단계. 핵심 요약 - 언제 뭘 쓸까

Flexbox를 쓰는 경우: 한 줄의 요소들을 정렬하고 싶을 때. 네비게이션 바, 버튼 그룹, 상단 탭 메뉴 등이 전형적인 예다. 아이템 개수가 정해지지 않았거나 동적으로 변할 때도 Flexbox가 낫다.

Grid를 쓰는 경우: 2차원 레이아웃이 필요할 때. 웹사이트 전체 구조(헤더/사이드바/메인/푸터), 대시보드, 상품 갤러리, 데이터 테이블 같은 복잡한 레이아웃에 최적이다.

둘 다 쓰는 경우: Grid로 큰 틀을 잡고, Flexbox로 세부 정렬을 한다. 특히 카드형 레이아웃이나 대시보드에서 이 패턴이 자주 나타난다.

레이아웃은 성능과 유지보수성을 크게 좌우한다. Flexbox의 간결함과 Grid의 명확성 중 상황에 맞는 것을 골라 사용하면, 코드 복잡도를 줄이면서도 반응형 대응을 깔끔하게 할 수 있다. 이 글의 테이블과 예제들을 참고해서 다음 프로젝트에서는 어느 상황에 무엇을 쓸지 확신 있게 선택해보자.