Skip to main content
Summary

목록을 정리할 때 Grid가 편한 이유

웹페이지에는 비슷한 모양의 콘텐츠가 반복되는 영역이 많습니다. 쇼핑몰의 상품 목록, 블로그 글 목록, 포트폴리오 이미지 갤러리, 팀원 소개 카드가 그렇습니다.

이런 화면은 보통 한 줄에 여러 개의 카드를 놓고, 다음 줄로 자연스럽게 이어지게 만듭니다. 이때 CSS Grid를 사용하면 코드를 길게 쓰지 않고도 깔끔한 격자 구조를 만들 수 있습니다.

Grid는 이름 그대로 화면을 격자판처럼 나누는 배치 방식입니다. 바둑판이나 달력처럼 가로줄과 세로줄이 있다고 생각하면 됩니다. 각 카드가 그 칸 안에 하나씩 들어갑니다.

이전 장에서 배운 Flexbox가 "한 줄 안에서 요소를 어떻게 정렬할까?"에 강하다면, Grid는 "여러 줄과 여러 열로 이루어진 목록을 어떻게 배치할까?"에 강합니다.

간단히 구분하면 이렇습니다.

  • 메뉴, 버튼 묶음, 배너 안의 문구와 버튼 정렬 → Flexbox

  • 상품 카드 목록, 블로그 글 목록, 이미지 갤러리 → Grid

물론 실제 작업에서는 둘을 함께 쓰는 경우도 많습니다. 예를 들어 상품 목록 전체는 Grid로 배치하고, 각 상품 카드 안의 가격과 버튼은 Flexbox로 정렬할 수 있습니다.

Grid로 카드 목록과 갤러리 배치하기AI 생성 이미지

Grid는 부모에게 적용한다

Flexbox와 마찬가지로 Grid도 정렬하고 싶은 요소 하나하나에 적용하지 않습니다. 카드들을 감싸는 부모 요소에 적용합니다.

예를 들어 상품 카드가 여러 개 있을 때 구조는 보통 이렇게 생겼습니다.

<div class='product-grid'>
  <div class='product-card'>상품 1</div>
  <div class='product-card'>상품 2</div>
  <div class='product-card'>상품 3</div>
  <div class='product-card'>상품 4</div>
</div>

여기서 실제로 Grid를 적용할 대상은 .product-card가 아니라, 카드들을 감싸는 .product-grid입니다.

.product-grid {
  display: grid;
}

display: grid;는 "이 안의 자식 요소들을 격자로 배치하겠다"는 뜻입니다. 아직은 큰 변화가 없어 보일 수 있습니다. 몇 열로 나눌지 정하지 않았기 때문입니다.

Grid는 보통 다음 순서로 작성합니다.

  1. 부모에 display: grid;를 쓴다.

  2. grid-template-columns로 열의 개수를 정한다.

  3. gap으로 카드 사이 간격을 정한다.

이 세 가지만 알아도 대부분의 카드 목록을 만들 수 있습니다.

grid-template-columns로 열 만들기

grid-template-columns는 Grid에서 세로 열을 어떻게 나눌지 정하는 속성입니다. 이름이 길지만 의미는 단순합니다.

  • grid → 격자

  • template → 틀

  • columns → 열

즉, "격자의 열 모양을 정한다"는 뜻입니다.

상품 카드를 2열로 배치하고 싶다면 이렇게 씁니다.

.product-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

여기서 1fr이라는 새 단위가 나왔습니다. fr은 Grid에서 사용하는 비율 단위입니다. 쉽게 말해 "남은 공간을 몇 조각으로 나눌까?"를 뜻합니다.

1fr 1fr은 가로 공간을 똑같이 2조각으로 나눈다는 의미입니다. 그래서 카드가 2열로 배치됩니다.

3열로 만들고 싶다면 이렇게 바꿉니다.

.product-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 20px;
}

1fr을 세 번 썼으므로 가로 공간이 3등분됩니다.

카드가 6개 있다면 3개는 첫 줄에, 나머지 3개는 다음 줄에 놓입니다. 카드가 8개라면 첫 줄 3개, 둘째 줄 3개, 셋째 줄 2개처럼 자연스럽게 이어집니다.

gap으로 간격을 한 번에 조정하기

카드 목록을 만들 때 자주 생기는 문제가 있습니다. 카드 사이 간격이 들쭉날쭉해지는 것입니다.

예전 방식으로는 각 카드에 margin을 주어 간격을 만들기도 했습니다. 하지만 카드가 여러 줄로 늘어나면 위아래 간격과 좌우 간격을 맞추기 번거롭습니다.

Grid에서는 부모에 gap을 쓰면 됩니다.

.product-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 24px;
}

gap: 24px;은 카드 사이의 가로 간격과 세로 간격을 모두 24px로 맞춥니다. 카드마다 따로 여백을 줄 필요가 없습니다.

가로와 세로 간격을 다르게 주고 싶다면 값을 두 개 쓸 수 있습니다.

.product-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 32px 20px;
}

이 경우 첫 번째 값 32px은 위아래 간격, 두 번째 값 20px은 좌우 간격입니다.

처음에는 값을 하나만 쓰는 방식부터 익히는 것이 좋습니다. 대부분의 카드 목록에서는 gap: 20px; 또는 gap: 24px; 정도만으로도 충분히 정돈됩니다.

repeat으로 같은 값을 짧게 쓰기

3열 목록을 만들 때 1fr 1fr 1fr처럼 같은 값을 반복해서 쓰면 조금 길어 보입니다. 이럴 때 repeat()을 사용할 수 있습니다.

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

repeat(3, 1fr)은 "1fr을 3번 반복한다"는 뜻입니다. 결과는 1fr 1fr 1fr과 같습니다.

2열이면 이렇게 씁니다.

.product-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
}

4열이면 숫자만 바꾸면 됩니다.

.product-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
}

비개발자가 템플릿을 수정할 때도 이 부분은 자주 보게 됩니다. repeat(3, 1fr)을 repeat(4, 1fr)로 바꾸면 한 줄에 보이는 카드 수가 3개에서 4개로 늘어납니다.

다만 열이 많아질수록 각 카드의 폭은 좁아집니다. 상품명이나 설명이 긴 카드라면 4열보다 3열이 더 읽기 좋을 수 있습니다.

minmax로 카드가 너무 작아지는 문제 막기

repeat(3, 1fr)은 간단하지만 한 가지 문제가 있습니다. 화면이 좁아져도 계속 3열을 유지하려고 합니다. 모바일 화면에서는 카드가 너무 좁아져 글자가 읽기 어려워질 수 있습니다.

이때 사용하는 패턴이 있습니다.

.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 24px;
}

처음 보면 길어 보이지만, 의미를 나누면 이해하기 쉽습니다.

minmax(240px, 1fr)은 "카드 한 칸의 최소 크기는 240px, 가능하면 남은 공간을 나누어 넓게 쓰겠다"는 뜻입니다.

  • 240px → 카드가 이보다 너무 작아지지 않게 하는 최소 폭

  • 1fr → 공간이 남으면 비율에 맞게 넓어지는 폭

auto-fit은 화면 너비에 맞춰 들어갈 수 있는 만큼 열을 자동으로 배치하라는 뜻입니다.

그래서 이 코드는 다음처럼 동작합니다.

  • 넓은 화면에서는 3열 또는 4열로 보인다.

  • 중간 화면에서는 2열로 줄어든다.

  • 좁은 모바일 화면에서는 1열로 내려간다.

즉, 열 개수를 손으로 계속 바꾸지 않아도 화면 너비에 따라 카드 수가 자연스럽게 달라집니다. 반응형 웹페이지를 만들 때 자주 쓰는 Grid 패턴입니다.

지금은 이 문장을 외우기보다 결과를 기억하면 됩니다.

카드 목록이 화면 너비에 맞게 알아서 줄바꿈되게 하고 싶다면 repeat(auto-fit, minmax(240px, 1fr))를 떠올리세요.

상품 목록 카드 만들기

이제 실제 상품 목록처럼 보이는 예제를 만들어 보겠습니다. 완성 결과는 한 줄에 여러 상품 카드가 놓이고, 화면이 좁아지면 카드가 자연스럽게 다음 줄로 내려가는 구조입니다.

먼저 Grid 부모를 만듭니다.

.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 24px;
}

이 코드만으로 상품 카드들은 격자 구조로 배치됩니다. 이제 카드 자체를 조금 꾸며 보겠습니다.

.product-card {
  padding: 20px;
  border: 1px solid #e5e7eb;
  border-radius: 16px;
  background-color: #ffffff;
}

여기서는 이전 장에서 배운 속성들이 다시 등장합니다.

  • padding은 카드 안쪽 여백입니다.

  • border는 카드의 경계를 보여 줍니다.

  • border-radius는 모서리를 둥글게 만듭니다.

  • background-color는 카드 배경색입니다.

이미지가 있는 상품 카드라면 이미지도 카드 폭에 맞춰야 합니다.

.product-card img {
  width: 100%;
  border-radius: 12px;
}

width: 100%;는 이미지가 카드의 가로폭을 넘지 않게 해 줍니다. 상품 이미지가 카드 밖으로 삐져나오는 문제를 막을 때 자주 사용합니다.

제목과 가격도 간단히 정리해 보겠습니다.

.product-card h3 {
  margin: 16px 0 8px;
  font-size: 18px;
}

.product-card .price {
  font-weight: 700;
  color: #2563eb;
}

이제 상품 목록은 단순히 아래로 쌓인 문서가 아니라 쇼핑몰에서 볼 수 있는 카드형 목록에 가까워집니다.

포트폴리오 갤러리 만들기

Grid는 이미지 갤러리에도 잘 어울립니다. 포트폴리오, 여행 사진, 인테리어 시공 사례처럼 이미지를 여러 장 보여 주는 화면에서 특히 유용합니다.

가장 기본적인 갤러리 CSS는 다음과 같습니다.

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
}

이미지는 각 칸에 꽉 차게 넣습니다.

.gallery img {
  width: 100%;
  height: 180px;
  object-fit: cover;
  border-radius: 12px;
}

여기서 object-fit: cover;는 이미지를 정해진 영역에 꽉 차게 보여 주는 속성입니다. 액자에 사진을 넣는다고 생각하면 됩니다. 사진의 비율이 조금 달라도 빈 공간 없이 채워지지만, 일부 가장자리가 잘릴 수 있습니다.

이미지가 찌그러지는 것보다 자연스럽게 잘리는 편이 갤러리에서는 더 보기 좋을 때가 많습니다.

사진 전체가 잘리지 않고 모두 보여야 하는 경우에는 object-fit: contain;을 사용할 수도 있습니다. 다만 이 경우 이미지 주변에 빈 공간이 생길 수 있습니다.

Flexbox와 Grid를 고르는 간단한 기준

Flexbox와 Grid 중 무엇을 써야 할지 헷갈릴 수 있습니다. 처음에는 아래 기준으로 고르면 됩니다.

한 방향 정렬이면 Flexbox가 편합니다.

  • 헤더에서 로고와 메뉴를 가로로 놓기

  • 버튼 두 개를 나란히 놓기

  • 배너 문구와 버튼을 양쪽 끝에 배치하기

  • 카드 안에서 가격과 버튼을 한 줄로 정렬하기

여러 행과 열의 목록이면 Grid가 편합니다.

  • 상품 카드 목록

  • 블로그 글 카드 목록

  • 포트폴리오 이미지 갤러리

  • 팀원 소개 카드

  • 후기 카드 모음

중요한 것은 둘 중 하나만 써야 한다는 생각을 버리는 것입니다. Grid는 큰 목록의 구조를 잡고, Flexbox는 그 안의 작은 정렬을 다듬는 식으로 함께 사용할 수 있습니다.

자주 하는 실수 체크리스트

Grid를 처음 사용할 때는 다음 부분에서 실수가 자주 납니다.

  • display: grid;를 카드 하나에 적용했다.

    • 카드들을 감싸는 부모 요소에 적용해야 합니다.

  • grid-template-columns를 쓰지 않았다.

    • 열 구조를 정하지 않으면 원하는 격자 모양이 나오지 않을 수 있습니다.

  • 카드 사이 간격을 카드의 margin으로 각각 조정했다.

    • Grid 부모에 gap을 쓰면 더 단순합니다.

  • repeat(4, 1fr)로 열을 너무 많이 만들었다.

    • 카드가 좁아져 글자가 답답해질 수 있습니다.

  • 이미지에 width: 100%;를 주지 않았다.

    • 큰 이미지가 카드 밖으로 튀어나올 수 있습니다.

  • 모바일에서 카드가 너무 작다.

    • repeat(auto-fit, minmax(220px, 1fr)) 같은 패턴을 사용해 보세요.

작은 실습: 블로그 글 목록을 Grid로 바꾸기

이번 실습에서는 블로그 글 카드 6개가 있다고 생각해 보겠습니다. 수정 전에는 카드가 아래로 길게 쌓여 있습니다.

수정 전 CSS입니다.

.post-list {
  max-width: 960px;
  margin: 0 auto;
}

.post-card {
  padding: 20px;
  margin-bottom: 20px;
  border: 1px solid #e5e7eb;
  border-radius: 16px;
}

이 방식도 틀린 것은 아닙니다. 다만 PC 화면에서는 가로 공간이 많이 남습니다. 같은 크기의 카드가 반복된다면 Grid로 바꾸는 편이 더 정돈되어 보입니다.

수정 후 CSS입니다.

.post-list {
  max-width: 960px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 24px;
}

.post-card {
  padding: 20px;
  border: 1px solid #e5e7eb;
  border-radius: 16px;
}

달라진 점은 세 가지입니다.

첫째, .post-list에 display: grid;를 추가했습니다. 이제 이 안의 글 카드들이 격자로 배치됩니다.

둘째, grid-template-columns로 카드의 최소 폭을 정했습니다. 한 카드가 최소 260px은 확보하도록 했기 때문에 너무 좁아지는 일을 줄일 수 있습니다.

셋째, 카드마다 있던 margin-bottom을 없애고 부모에 gap: 24px;를 주었습니다. 이제 카드 사이 간격은 한 곳에서 관리됩니다.

수정 전후 비교

수정 전에는 카드가 한 줄에 하나씩만 보여서 PC 화면에서 목록이 길게 늘어졌습니다. 아래로 스크롤해야 하는 양도 많았습니다.

수정 후에는 화면 너비에 따라 카드가 2열 또는 3열로 정리됩니다. 같은 글 목록이라도 훨씬 가볍고 보기 좋게 느껴집니다. 모바일에서는 자동으로 1열에 가까운 구조가 되어 글을 읽기에도 편합니다.

이번 장의 핵심은 단순합니다. 반복되는 카드나 이미지가 많다면 먼저 Grid를 떠올리세요. 부모에 display: grid;, 열에는 grid-template-columns, 간격에는 gap을 사용하면 목록 화면의 절반은 이미 정리된 것입니다.

책 목록

비개발자를 위한 CSS 입문: 눈으로 이해하고 바로 고치는 쉬운 스타일링

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기