웹 개발·4분 읽기

CSS Grid와 Flexbox 완벽 가이드: 모던 레이아웃의 모든 것

CSS Grid와 Flexbox의 핵심 개념, 차이점, 실전 활용법을 상세히 비교하고 반응형 레이아웃을 만드는 방법을 예제와 함께 알아봅니다.

공유:

CSS Grid와 Flexbox 완벽 가이드: 모던 레이아웃의 모든 것

웹 페이지의 레이아웃을 구성하는 일은 프론트엔드 개발의 핵심입니다. 과거에는 floatposition, 테이블 레이아웃 등을 사용해 복잡한 핵(hack)을 동원해야 했지만, 이제는 CSS Grid와 Flexbox라는 강력한 도구가 있습니다. 이 두 가지 레이아웃 시스템을 제대로 이해하면 거의 모든 디자인을 구현할 수 있습니다. 이 글에서는 각각의 개념과 용도, 그리고 실전에서 어떻게 함께 사용하는지 깊이 있게 다루겠습니다.

Flexbox: 1차원 레이아웃의 왕

Flexbox(Flexible Box Layout)는 1차원 레이아웃 시스템입니다. 한 번에 하나의 축(가로 또는 세로)을 기준으로 아이템을 배치합니다. 네비게이션 바, 카드 정렬, 센터링 등 한 방향으로의 레이아웃에 탁월한 성능을 발휘합니다.

Flexbox 기본 개념

Flexbox를 사용하려면 부모 요소(flex container)에 display: flex를 선언합니다. 그러면 자식 요소(flex items)들이 flex 아이템이 됩니다.

.container {
  display: flex;
}

이것만으로도 자식 요소들이 가로로 나란히 배치됩니다. 이제 다양한 속성으로 세밀하게 제어할 수 있습니다.

주축과 교차축

Flexbox에는 두 개의 축이 있습니다.

  • 주축(Main Axis): 아이템이 배치되는 기본 방향입니다. flex-direction으로 결정됩니다.
  • 교차축(Cross Axis): 주축에 수직인 방향입니다.
.container {
  display: flex;
  flex-direction: row;          /* 기본값: 가로 방향 */
  /* flex-direction: column; */ /* 세로 방향 */
  /* flex-direction: row-reverse; */
  /* flex-direction: column-reverse; */
}

Flex Container 속성들

부모 요소에 적용하는 주요 속성들을 살펴보겠습니다.

.container {
  display: flex;

  /* 주축 방향 아이템 정렬 */
  justify-content: flex-start;    /* 시작점 정렬 (기본값) */
  justify-content: center;        /* 가운데 정렬 */
  justify-content: flex-end;      /* 끝점 정렬 */
  justify-content: space-between; /* 아이템 사이 균등 배분 */
  justify-content: space-around;  /* 아이템 주위 균등 배분 */
  justify-content: space-evenly;  /* 완전 균등 배분 */

  /* 교차축 방향 아이템 정렬 */
  align-items: stretch;     /* 늘려서 채움 (기본값) */
  align-items: flex-start;  /* 교차축 시작점 */
  align-items: center;      /* 교차축 가운데 */
  align-items: flex-end;    /* 교차축 끝점 */
  align-items: baseline;    /* 텍스트 베이스라인 */

  /* 줄바꿈 설정 */
  flex-wrap: nowrap;  /* 줄바꿈 없음 (기본값) */
  flex-wrap: wrap;    /* 넘치면 다음 줄로 */

  /* 여러 줄일 때 교차축 정렬 */
  align-content: flex-start;
  align-content: center;
  align-content: space-between;

  /* 아이템 간 간격 */
  gap: 16px;           /* 모든 방향 */
  row-gap: 16px;       /* 세로 간격 */
  column-gap: 24px;    /* 가로 간격 */
}

Flex Item 속성들

자식 요소에 적용하는 속성으로 개별 아이템의 크기와 동작을 제어합니다.

.item {
  /* 아이템이 커질 수 있는 비율 (기본값: 0) */
  flex-grow: 1;

  /* 아이템이 줄어들 수 있는 비율 (기본값: 1) */
  flex-shrink: 0;

  /* 아이템의 기본 크기 */
  flex-basis: 200px;

  /* 축약형: flex-grow flex-shrink flex-basis */
  flex: 1 0 200px;

  /* 개별 아이템 교차축 정렬 */
  align-self: center;

  /* 배치 순서 */
  order: -1;  /* 숫자가 작을수록 앞으로 */
}

Flexbox 실전 예제: 네비게이션 바

.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 24px;
  height: 64px;
  background-color: #1a1a2e;
}

.nav-logo {
  flex-shrink: 0;
}

.nav-links {
  display: flex;
  gap: 24px;
  list-style: none;
}

.nav-actions {
  display: flex;
  gap: 12px;
  align-items: center;
}

이 예제에서 로고는 왼쪽, 네비게이션 링크는 가운데, 액션 버튼은 오른쪽에 배치됩니다. space-between이 세 그룹을 양 끝과 가운데로 분산시킵니다.

완벽한 센터링

Flexbox의 가장 유용한 기능 중 하나는 간단한 센터링입니다. 과거에는 복잡한 트릭이 필요했지만, 이제는 두 줄이면 됩니다.

.center-container {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

CSS Grid: 2차원 레이아웃의 혁명

CSS Grid는 2차원 레이아웃 시스템입니다. 행(row)과 열(column)을 동시에 제어할 수 있어, 복잡한 페이지 레이아웃을 직관적으로 구성할 수 있습니다. 전체 페이지 구조, 대시보드, 갤러리 등에 적합합니다.

Grid 기본 개념

Grid를 사용하려면 부모 요소에 display: grid를 선언하고, 행과 열의 크기를 정의합니다.

.grid-container {
  display: grid;
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: auto 1fr auto;
  gap: 16px;
}

위 코드는 3열 레이아웃을 생성합니다. 왼쪽과 오른쪽은 200px 고정 너비, 가운데는 남은 공간을 모두 차지합니다(1fr).

fr 단위 이해하기

fr(fraction)은 Grid 전용 단위로, 사용 가능한 공간의 비율을 나타냅니다.

.grid {
  display: grid;

  /* 3개의 동일한 너비 열 */
  grid-template-columns: 1fr 1fr 1fr;

  /* 축약형 */
  grid-template-columns: repeat(3, 1fr);

  /* 첫 번째 열이 두 배 넓음 */
  grid-template-columns: 2fr 1fr 1fr;

  /* 고정 너비와 혼합 */
  grid-template-columns: 250px 1fr 250px;
}

Grid 영역(Area) 이름 지정

Grid의 가장 직관적인 기능 중 하나는 영역에 이름을 부여하여 레이아웃을 시각적으로 정의하는 것입니다.

.page-layout {
  display: grid;
  grid-template-areas:
    "header header header"
    "sidebar main aside"
    "footer footer footer";
  grid-template-columns: 250px 1fr 200px;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
  gap: 16px;
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.aside   { grid-area: aside; }
.footer  { grid-area: footer; }

마치 아스키 아트처럼 레이아웃의 구조를 한눈에 파악할 수 있습니다. 이 방식은 코드의 가독성을 크게 높여줍니다.

Grid 아이템 배치

개별 아이템의 위치를 라인 번호로 지정할 수도 있습니다.

.item {
  /* 열 라인 1에서 3까지 (2개 열 차지) */
  grid-column: 1 / 3;

  /* 또는 span 사용 */
  grid-column: span 2;

  /* 행 라인 1에서 3까지 (2개 행 차지) */
  grid-row: 1 / 3;
}

반응형 Grid: auto-fill과 auto-fit

Grid의 강력한 기능 중 하나는 미디어 쿼리 없이도 반응형 레이아웃을 만들 수 있다는 점입니다.

/* 최소 300px, 최대 1fr의 열을 자동으로 생성 */
.responsive-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 24px;
}

auto-fill은 가능한 많은 열을 채우고 빈 공간을 남기며, auto-fit은 아이템이 적을 때 빈 트랙을 접어서 아이템을 늘립니다.

/* auto-fill: 빈 트랙도 공간을 차지 */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));

/* auto-fit: 빈 트랙은 0으로 접힘 */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));

Grid 실전 예제: 카드 갤러리

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

.card {
  display: flex;
  flex-direction: column;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: transform 0.2s, box-shadow 0.2s;
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}

.card-body {
  flex: 1;
  padding: 16px;
}

.card-footer {
  padding: 12px 16px;
  margin-top: auto;
  border-top: 1px solid #eee;
}

여기서 주목할 점은 Grid와 Flexbox를 함께 사용하고 있다는 것입니다. 카드 갤러리의 전체 배치는 Grid로, 개별 카드 내부 구조는 Flexbox로 처리합니다.

Grid vs Flexbox: 언제 무엇을 쓸까?

두 레이아웃 시스템은 경쟁 관계가 아니라 보완 관계입니다. 각각의 강점이 있으므로 상황에 맞게 선택하면 됩니다.

Flexbox를 선택해야 할 때

  • 한 방향(1차원) 배치: 요소들을 가로 또는 세로로 나열할 때
  • 콘텐츠 기반 크기: 아이템 크기가 콘텐츠에 따라 유동적일 때
  • 네비게이션, 툴바: 아이템을 한 줄로 정렬하고 간격을 조절할 때
  • 센터링: 수평/수직 가운데 정렬이 필요할 때
  • 아이템 간 동적 공간 분배: flex-grow, flex-shrink로 유연한 크기 조절이 필요할 때

Grid를 선택해야 할 때

  • 2차원 배치: 행과 열 모두 제어해야 할 때
  • 전체 페이지 레이아웃: 헤더, 사이드바, 메인, 푸터 등의 구조
  • 정밀한 배치: 아이템의 정확한 위치를 지정해야 할 때
  • 겹침(Overlap): 아이템을 겹치게 배치해야 할 때
  • 균일한 그리드: 카드 갤러리, 이미지 그리드 등

함께 사용하는 실전 패턴

실무에서는 Grid와 Flexbox를 함께 사용하는 것이 일반적입니다. 전체 페이지 구조는 Grid로 잡고, 각 영역 내부의 요소 배치는 Flexbox로 처리합니다.

/* 전체 페이지: Grid */
.page {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  grid-template-columns: 280px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

/* 헤더 내부: Flexbox */
.header {
  grid-area: header;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 24px;
}

/* 메인 영역 내 카드 그리드: Grid */
.main {
  grid-area: main;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
  padding: 24px;
}

/* 개별 카드 내부: Flexbox */
.card {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

반응형 레이아웃 완성하기

실제 프로젝트에서는 미디어 쿼리와 함께 사용하여 다양한 화면 크기에 대응합니다.

.page {
  display: grid;
  grid-template-areas:
    "header"
    "main"
    "sidebar"
    "footer";
  grid-template-columns: 1fr;
  min-height: 100vh;
}

/* 태블릿 이상 */
@media (min-width: 768px) {
  .page {
    grid-template-areas:
      "header header"
      "sidebar main"
      "footer footer";
    grid-template-columns: 250px 1fr;
  }
}

/* 데스크톱 */
@media (min-width: 1200px) {
  .page {
    grid-template-areas:
      "header header header"
      "sidebar main aside"
      "footer footer footer";
    grid-template-columns: 250px 1fr 200px;
    max-width: 1400px;
    margin: 0 auto;
  }
}

모바일에서는 모든 영역이 세로로 쌓이고, 태블릿에서는 사이드바와 메인이 나란히 배치되며, 데스크톱에서는 3열 레이아웃으로 확장됩니다. grid-template-areas를 사용하면 각 브레이크포인트에서의 레이아웃 변경을 시각적으로 이해하기 쉽습니다.

유용한 레이아웃 패턴 모음

실무에서 자주 사용하는 레이아웃 패턴들을 정리합니다.

Holy Grail 레이아웃 (성배 레이아웃)

헤더, 푸터, 사이드바 두 개, 메인 콘텐츠로 구성된 클래식한 웹 페이지 구조입니다.

.holy-grail {
  display: grid;
  grid-template: auto 1fr auto / 200px 1fr 200px;
  grid-template-areas:
    "header header header"
    "left   main   right"
    "footer footer footer";
  min-height: 100vh;
}

Sticky Footer

콘텐츠가 적어도 푸터가 항상 화면 하단에 위치하는 패턴입니다.

.sticky-footer-layout {
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

균등 높이 카드

같은 행의 카드들이 콘텐츠 양에 관계없이 동일한 높이를 갖는 패턴입니다.

.equal-height-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.card {
  display: flex;
  flex-direction: column;
}

.card-content {
  flex: 1;
}

.card-action {
  margin-top: auto;
}

Grid가 행 내의 높이를 자동으로 맞추고, 카드 내부에서는 Flexbox의 margin-top: auto로 버튼을 하단에 고정합니다.

마무리

CSS Grid와 Flexbox는 모던 웹 레이아웃의 양대 축입니다. 핵심을 요약하면 다음과 같습니다.

  • Flexbox는 한 방향(1차원) 레이아웃에 최적화되어 있으며, 콘텐츠 정렬과 공간 분배에 강합니다.
  • CSS Grid는 행과 열(2차원)을 동시에 제어하며, 전체 페이지 레이아웃에 이상적입니다.
  • 함께 사용하는 것이 가장 효과적입니다. 매크로 레이아웃은 Grid로, 마이크로 레이아웃은 Flexbox로 구성하세요.
  • auto-fit/auto-fillminmax()를 활용하면 미디어 쿼리 없이도 반응형 레이아웃을 만들 수 있습니다.

이 두 가지 도구를 자유자재로 사용할 수 있게 되면, 어떤 디자인이든 CSS만으로 구현할 수 있는 자신감을 갖게 될 것입니다. 연습 삼아 자주 방문하는 웹사이트의 레이아웃을 Grid와 Flexbox로 재현해보는 것을 추천합니다.

#CSS#Grid#Flexbox#레이아웃#반응형