개요

CSS Grid는 2차원 레이아웃 시스템으로, 복잡한 웹 레이아웃을 깔끔하게 구현할 수 있게 합니다. 2023년부터 모든 주요 브라우저에서 Subgrid가 지원되면서, Grid의 진가가 완전히 발휘되고 있습니다. Flexbox가 1차원(행 또는 열)이라면 Grid는 2차원(행과 열 동시)을 다루며, 복잡한 대시보드, 카드 레이아웃, 매거진 스타일 페이지에 최적화되어 있습니다.

핵심 개념

Grid Containerdisplay: grid를 적용한 부모 요소이며, Grid Item은 그 직접 자식 요소들입니다. grid-template-columnsgrid-template-rows로 그리드 트랙을 정의합니다.

fr 단위는 사용 가능한 공간의 비율을 나타냅니다. 1fr 2fr는 1:2 비율로 공간을 분배합니다.

Grid Lines는 그리드를 구성하는 선으로, 아이템 배치 시 참조합니다. 숫자 또는 이름으로 지정할 수 있습니다.

Subgrid는 중첩된 그리드가 부모 그리드의 트랙을 상속받아, 여러 계층의 요소를 하나의 그리드 시스템에 정렬할 수 있게 합니다.

실전 예제

기본적인 그리드 레이아웃을 구현합니다.

/* 기본 그리드 */
.grid-container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto;
  gap: 1rem;
}

/* 반응형 그리드 - auto-fit, minmax 활용 */
.responsive-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1.5rem;
}

/* 명시적 행/열 정의 */
.explicit-grid {
  display: grid;
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: 80px 1fr 60px;
  min-height: 100vh;
}

/* Grid Template Areas로 레이아웃 정의 */
.page-layout {
  display: grid;
  grid-template-areas:
    "header header header"
    "sidebar main aside"
    "footer footer footer";
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: 80px 1fr 60px;
  gap: 1rem;
  min-height: 100vh;
}

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

복잡한 그리드 아이템 배치를 구현합니다.

/* 12컬럼 그리드 시스템 */
.container {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 1rem;
}

/* 그리드 라인으로 배치 */
.item-1 {
  grid-column: 1 / 7;  /* 1번 라인부터 7번 라인까지 (6컬럼) */
  grid-row: 1 / 3;     /* 2행 차지 */
}

.item-2 {
  grid-column: 7 / -1;  /* 7번 라인부터 마지막까지 */
}

/* span 키워드 사용 */
.item-3 {
  grid-column: span 4;  /* 4컬럼 차지 */
  grid-row: span 2;     /* 2행 차지 */
}

/* 이름 있는 라인 */
.named-grid {
  display: grid;
  grid-template-columns:
    [sidebar-start] 200px
    [sidebar-end main-start] 1fr
    [main-end aside-start] 200px
    [aside-end];
}

.sidebar { grid-column: sidebar-start / sidebar-end; }
.main { grid-column: main-start / main-end; }
.aside { grid-column: aside-start / aside-end; }

Subgrid를 활용한 카드 정렬입니다.

/* 부모 그리드 */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
}

/* 자식 그리드 - 부모 그리드 행을 상속 */
.card {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 4; /* 4개 행 트랙 차지 */
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  overflow: hidden;
}

.card__image {
  /* 첫 번째 행 */
}

.card__title {
  /* 두 번째 행 - 모든 카드에서 정렬됨 */
  padding: 1rem;
}

.card__description {
  /* 세 번째 행 - 모든 카드에서 정렬됨 */
  padding: 0 1rem;
}

.card__actions {
  /* 네 번째 행 - 모든 카드에서 정렬됨 */
  padding: 1rem;
  margin-top: auto;
}
<div class="card-grid">
  <article class="card">
    <img class="card__image" src="1.jpg" alt="">
    <h3 class="card__title">짧은 제목</h3>
    <p class="card__description">설명 텍스트</p>
    <div class="card__actions">
      <button>자세히 보기</button>
    </div>
  </article>

  <article class="card">
    <img class="card__image" src="2.jpg" alt="">
    <h3 class="card__title">이것은 매우 긴 제목이며 여러 줄을 차지합니다</h3>
    <p class="card__description">설명 텍스트</p>
    <div class="card__actions">
      <button>자세히 보기</button>
    </div>
  </article>
</div>

Subgrid를 활용하면 제목 길이가 다르더라도 모든 카드의 버튼이 같은 높이에 정렬됩니다.

고급 Grid 기법: 매거진 레이아웃입니다.

.magazine-layout {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-auto-rows: 200px;
  gap: 1rem;
}

.article-1 {
  grid-column: 1 / 4;
  grid-row: 1 / 3;
}

.article-2 {
  grid-column: 4 / 7;
  grid-row: 1 / 2;
}

.article-3 {
  grid-column: 4 / 7;
  grid-row: 2 / 3;
}

.article-4 {
  grid-column: 1 / 3;
  grid-row: 3 / 4;
}

.article-5 {
  grid-column: 3 / 5;
  grid-row: 3 / 4;
}

.article-6 {
  grid-column: 5 / 7;
  grid-row: 3 / 4;
}

/* 반응형 조정 */
@media (max-width: 768px) {
  .magazine-layout {
    grid-template-columns: 1fr;
    grid-auto-rows: auto;
  }

  .article-1,
  .article-2,
  .article-3,
  .article-4,
  .article-5,
  .article-6 {
    grid-column: 1;
    grid-row: auto;
  }
}

Grid 정렬 속성을 활용합니다.

.grid-container {
  display: grid;
  grid-template-columns: repeat(3, 200px);
  grid-template-rows: repeat(2, 150px);
  gap: 1rem;

  /* 컨테이너 내 그리드 정렬 */
  justify-content: center;  /* 수평: start, end, center, space-between, space-around */
  align-content: center;    /* 수직: start, end, center, space-between, space-around */

  /* 아이템 기본 정렬 */
  justify-items: stretch;   /* 수평: start, end, center, stretch */
  align-items: stretch;     /* 수직: start, end, center, stretch */
}

/* 개별 아이템 정렬 */
.item-special {
  justify-self: center;
  align-self: end;
}

활용 팁

  • auto-fit vs auto-fill: auto-fit은 빈 트랙을 축소하고, auto-fill은 빈 트랙을 유지합니다. 반응형 갤러리에는 auto-fit이 적합합니다.
  • Subgrid 폴백: Subgrid를 지원하지 않는 브라우저를 위해 @supports (grid-template-rows: subgrid)로 분기하세요.
  • Grid vs Flexbox: 2차원 레이아웃이나 명시적 배치가 필요하면 Grid, 1차원 흐름이나 콘텐츠 크기 기반 배치는 Flexbox를 사용하세요.
  • DevTools: Chrome과 Firefox DevTools의 Grid 인스펙터를 활용하면 그리드 라인과 영역을 시각적으로 확인할 수 있습니다.
  • minmax(): minmax(200px, 1fr)로 최소/최대 크기를 제한하여 반응형 레이아웃을 쉽게 만드세요.

마무리

CSS Grid는 복잡한 레이아웃을 가장 간결하게 구현하는 도구입니다. Subgrid의 등장으로 중첩된 컴포넌트 정렬 문제가 완전히 해결되었고, auto-fit과 minmax의 조합은 반응형 디자인을 혁신적으로 간소화합니다. Float와 Position 기반 레이아웃은 이제 역사가 되었으며, Grid와 Flexbox가 현대 웹 레이아웃의 양대 축입니다.