CSS Grid의 repeat, minmax, auto-fit으로 카드 열을 어떻게 맞추나요?
CSS Grid는 카드의 행과 열을 함께 맞춥니다. repeat로 열을 반복하고 minmax로 폭 범위를 정하며 auto-fit으로 열 수를 조절합니다. 카드 수와 화면 폭을 바꿔 배치를 비교합니다.
적용 조건·범위: 반복 카드가 여러 행으로 늘어날 때 Grid를 선택하는 기준을 다룹니다.
독립 실습: 직접 만들고 확인하기
CSS Grid 실습: Flex 학습 카드로 열 맞추기와 auto-fit 비교 · 독립 실습
폭을 바꾸며 Grid 카드가 몇 개의 열로 나뉘는지 비교하세요.
예제 크게 보기 (새 탭).demo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: 16px; }
.demo-card { padding: 16px; border: 1px solid #777; }직접 실행: 환경 준비와 전체 파일
독자 질문
카드 수가 1개에서 4개로 늘어날 때 Flex 대신 Grid로 열과 행을 어떻게 자동 정렬할까요?
직접 만들 화면
폭에 따라 기능 카드가 한 열 또는 여러 열이 되고 카드 간격이 일정한 TaskFlow 기능 목록
새 폴더에 index.html과 style.css를 만들고 아래 전체 파일을 각각 저장하세요. 브라우저에서 index.html을 엽니다.
<!doctype html>
<html lang="ko">
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>CSS Grid 실습: Flex 학습 카드로 열 맞추기와 auto-fit 비교</title><link rel="stylesheet" href="./style.css"></head>
<body>
<section aria-labelledby="grid-title">
<h2 id="grid-title">TaskFlow 기능</h2>
<div class="demo-grid">
<article class="demo-card"><h3>빠른 입력</h3><p>할 일을 기록합니다.</p></article>
<article class="demo-card"><h3>우선순위</h3><p>중요한 일을 구분합니다.</p></article>
<article class="demo-card"><h3>완료 확인</h3><p>진행 상태를 봅니다.</p></article>
<article class="demo-card"><h3>보관</h3><p>지난 작업을 찾습니다.</p></article>
</div>
</section>
</body>
</html>
확인할 결과와 실제 검증 상태
넓은 화면에서는 가능한 수만큼 열이 생기고 360px에서는 각 카드가 컨테이너 폭에 맞는 한 열이어야 합니다. 카드 3개를 제거해 1개만 남겨 보고, auto-fit을 auto-fill로 바꿀 때 빈 트랙이 공간을 차지하는지도 비교하세요. 실제 폭 변화는 미검증입니다.
실제 브라우저·DevTools 조작 결과: 미확인. 위 내용은 코드에서 예상되는 결과와 독자가 수행할 확인 절차입니다.
다음 학습 연결
07회차에서는 이 Grid의 카드에 긴 URL을 넣고 가로 넘침을 해결합니다.
기본 Grid
.cards {
display: grid;
grid-template-columns:
repeat(3, 1fr);
gap: 16px;
}
3개의 동일한 열을 만듭니다.
작은 화면에서는 3열이 너무 좁을 수 있습니다.
minmax와 auto-fit
.cards {
display: grid;
grid-template-columns:
repeat(
auto-fit,
minmax(
min(100%, 220px),
1fr
)
);
gap: 16px;
}
카드 최소 폭을 유지하면서 공간이 충분하면 여러 열로 배치됩니다.
auto-fit과 auto-fill
둘 다 반복 가능한 열 개수를 자동 계산합니다.
차이는 빈 track을 처리하는 방식에서 드러납니다.
auto-fit
→ 빈 track을 접어 남은 공간을 기존 item이 확장
auto-fill
→ 가능한 track 공간을 유지
일반 카드 목록에서는 auto-fit이 자연스러운 경우가 많습니다.
Flex와 Grid 선택
header nav
button row
form action
→ Flex
feature cards
pricing cards
dashboard summary
→ Grid
모든 레이아웃을 Grid로 바꾸지 않습니다.

독립 예제
<div class="grid-demo">
<article>A</article>
<article>B</article>
<article>C</article>
<article>D</article>
</div>
.grid-demo {
display: grid;
grid-template-columns:
repeat(
auto-fit,
minmax(
min(100%, 180px),
1fr
)
);
gap: 16px;
}
자주 발생하는 오류
minmax 최소값이 viewport보다 큽니다
min(100%, 220px)처럼 작은 컨테이너에서 100%를 넘지 않도록 설계할 수 있습니다.
Grid child가 overflow합니다
7회차에서 min-width: 0, minmax(0, 1fr)를 자세히 다룹니다.
행 높이를 억지로 고정합니다
콘텐츠 길이가 달라질 수 있으면 고정 height를 최소화합니다.
학습 완료 체크리스트
- Flex와 Grid의 역할 차이를 설명할 수 있습니다.
- grid-template-columns를 작성할 수 있습니다.
- repeat와 minmax를 사용할 수 있습니다.
- auto-fit과 auto-fill의 차이를 기본적으로 이해했습니다.
- 카드 목록을 화면 폭에 따라 자연스럽게 재배치할 수 있습니다.
독립 실습은 여기서 마칠 수 있습니다. 아래 선택 실습은 TaskFlow 프로젝트 파일로 진행합니다.
선택 실습: 할 일 앱에 적용하기
TaskFlow는 간단한 서비스 화면에서 시작해 할 일 앱으로 이어 만드는 예제입니다. 이 선택 실습에서는 HTML과 CSS로 이번 화면을 만듭니다.
TaskFlow 기능 카드와 요금제 카드 구조를 Grid로 만듭니다.
선택: 연재 프로젝트와 전체 자료
연재 프로젝트를 이어 만드는 분을 위한 자료입니다. 이 글의 개념과 예제만 찾으셨다면 필요한 파일과 실행 방법만 펼쳐보세요.
TaskFlow 프로젝트 적용
CSS Grid 실습: Flex 학습 카드로 열 맞추기와 auto-fit 비교 · 단계별 TaskFlow
TaskFlow 누적 6단계입니다. 폭을 바꾸며 Grid 카드가 몇 개의 열로 나뉘는지 비교하세요.
예제 크게 보기 (새 탭)실행 가능한 시작본과 이번 단계
이번 단계 시작 ZIP을 새 폴더에 압축 해제합니다. 이 ZIP은 직전 단계의 완료 파일과 같으며 앞 글의 코드를 따로 모을 필요가 없습니다. 이번 단계 완료 ZIP은 다른 폴더에 풀어 비교합니다.
기능 카드의 Flex wrapper를 Grid로 바꾸고 Basic·Pro 요금제 카드를 추가합니다.
index.html: 이 파일의 기존 내용을 아래 완료 파일 전체와 대조하여 교체합니다. 다른 파일은 유지합니다.style.css: 이 파일의 기존 내용을 아래 완료 파일 전체와 대조하여 교체합니다. 다른 파일은 유지합니다.
짧은 코드 예제는 변경 위치를 설명합니다. 파일 전체를 작성하거나 교체할 때는 완료 파일 전체를 사용하세요. 생략 표시가 있는 부분 코드를 파일 전체로 저장하지 않습니다.
실행: ZIP의 index.html을 브라우저에서 엽니다. 외부 서버나 npm 설치 없이 로컬 HTML·CSS·이미지를 사용합니다. 문의 폼은 서버 전송을 연결하지 않은 문서 예제입니다. 연습 값만 사용하고 입력 형식을 확인합니다.
직접 확인할 결과: 기능 세 개와 요금제 두 개가 auto-fit/minmax 규칙을 공유합니다. 기존 배지·FAQ는 유지합니다.
전체 파일·코드 보기
완료 파일 전체
index.html 전체 파일
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>
TaskFlow
</title>
<link href="./style.css" rel="stylesheet"/>
</head>
<body>
<header class="site-header">
<div class="page site-header__inner">
<a class="brand" href="#home">
TaskFlow
</a>
<nav aria-label="주요 메뉴" class="nav">
<a href="#features">
기능
</a>
<a href="#contact">
문의
</a>
</nav>
</div>
</header>
<main class="page" id="home">
<section>
<h1>
해야 할 일을 한눈에 정리하세요
</h1>
<p>
TaskFlow는 오늘의 작업을 빠르게 정리하는 서비스입니다.
</p>
</section>
<section id="features">
<h2>
주요 기능
</h2>
<div class="feature-grid">
<article class="card feature-card">
<span class="feature-card__badge">
NEW
</span>
<h3>
빠른 작업 추가
</h3>
<p>
해야 할 일을 바로 기록할 수 있습니다.
</p>
</article>
<article class="card">
<h3>
간단한 분류
</h3>
<p>
해야 할 일을 구분합니다.
</p>
</article>
<article class="card">
<h3>
진행 확인
</h3>
<p>
완료 여부를 확인합니다.
</p>
</article>
</div>
</section>
<section class="faq" id="faq">
<h2>
자주 묻는 질문
</h2>
<details>
<summary>
TaskFlow는 어떤 서비스인가요?
</summary>
<p>
해야 할 일을 빠르게 정리하는 작업 관리 서비스 예제입니다.
</p>
</details>
<details>
<summary>
모바일에서도 볼 수 있나요?
</summary>
<p>
작은 화면부터 설계한 반응형 레이아웃을 사용합니다.
</p>
</details>
<details>
<summary>
문의는 어디서 하나요?
</summary>
<p>
아래 문의 폼을 이용할 수 있습니다.
</p>
</details>
</section>
<section id="pricing">
<h2>
요금제
</h2>
<div class="pricing-grid">
<article class="card">
<h3>
Basic
</h3>
<p>
개인 학습용
</p>
</article>
<article class="card">
<h3>
Pro
</h3>
<p>
더 많은 프로젝트
</p>
</article>
</div>
</section>
<section id="contact">
<h2>
문의하기
</h2>
<form>
<div class="form-field">
<label for="name">
이름
</label>
<input autocomplete="name" id="name" name="name" type="text"/>
</div>
<div class="form-field">
<label for="email">
이메일
</label>
<input autocomplete="email" id="email" name="email" type="email"/>
</div>
<div class="form-field">
<label for="message">
문의 내용
</label>
<textarea id="message" name="message" rows="5"></textarea>
</div>
<button type="submit">
문의 보내기
</button>
</form>
</section>
</main>
<footer class="site-footer">
<div class="page">
<p>
© TaskFlow
</p>
</div>
</footer>
<a class="help-button" href="#contact">
문의
</a>
</body>
</html>
style.css 전체 파일
:root {
color: #171717;
background: #f5f5f5;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
font-family:
Arial,
sans-serif;
line-height: 1.6;
color: #171717;
background: #f5f5f5;
}
.page {
width: min(
100% - 32px,
960px
);
margin-inline: auto;
}
.site-header,
.site-footer {
padding-block: 20px;
}
main {
padding-block: 48px;
}
section + section {
margin-top: 64px;
}
.card {
padding: 24px;
border: 1px solid #d7d7d7;
background: #fff;
}
form {
display: grid;
gap: 16px;
}
.form-field {
display: grid;
gap: 8px;
}
input,
textarea {
width: 100%;
min-height: 44px;
padding: 10px 12px;
border: 1px solid #b8b8b8;
background: #fff;
}
button {
min-height: 44px;
padding: 10px 16px;
border: 1px solid #171717;
background: #171717;
color: #fff;
}
a { color: inherit; }
input, textarea, button { font: inherit; }
h1 { font-size: 32px; font-weight: 700; }
h2 { font-size: 24px; }
h3 { font-size: 20px; }
.site-header__inner {
display: flex;
flex-direction: column;
gap: 12px;
}
.nav {
display: flex;
flex-wrap: wrap;
gap: 8px 16px;
}
.feature-list {
display: flex;
flex-direction: column;
gap: 16px;
}
@media (min-width: 48rem) {
.site-header__inner {
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.feature-list {
flex-direction: row;
}
.feature-list > * {
flex: 1;
}
}
.site-header {
position: sticky;
top: 0;
z-index: 10;
background: #f5f5f5;
border: 1px solid #ddd;
}
.feature-card {
position: relative;
}
.feature-card__badge {
position: absolute;
top: 12px;
right: 12px;
padding: 4px 8px;
border: 1px solid #171717;
background: #fff;
font-size: 12px;
}
.help-button {
position: fixed;
right: 16px;
bottom: 16px;
min-width: 44px;
min-height: 44px;
padding: 10px 14px;
border: 1px solid #171717;
background: #171717;
color: #fff;
text-decoration: none;
}
.faq {
display: grid;
gap: 12px;
}
.faq details {
border: 1px solid #d7d7d7;
background: #fff;
}
.faq summary {
padding: 16px;
cursor: pointer;
font-weight: 700;
}
.faq details p {
margin: 0;
padding: 0 16px 16px;
}
.faq summary:focus-visible {
outline: 2px solid #171717;
outline-offset: 2px;
}
.feature-grid,
.pricing-grid {
display: grid;
grid-template-columns:
repeat(
auto-fit,
minmax(
min(100%, 220px),
1fr
)
);
gap: 16px;
}
위 파일과 ZIP의 동명 파일은 동일합니다. 회차별 README·CHANGES 문서는 ZIP에 포함합니다. 생성 산출물·node_modules·실제 환경 변수 파일은 포함하지 않습니다.
index.html
기능 카드:
<div class="feature-grid">
<article class="card">
<h3>빠른 추가</h3>
<p>오늘 할 일을 바로 기록합니다.</p>
</article>
<article class="card">
<h3>우선순위</h3>
<p>중요한 작업을 구분합니다.</p>
</article>
<article class="card">
<h3>완료 확인</h3>
<p>진행 상태를 한눈에 확인합니다.</p>
</article>
</div>
요금제:
<section id="pricing">
<h2>요금제</h2>
<div class="pricing-grid">
<article class="card">
<h3>Basic</h3>
<p>개인 학습용</p>
</article>
<article class="card">
<h3>Pro</h3>
<p>더 많은 프로젝트</p>
</article>
</div>
</section>
style.css
.feature-grid,
.pricing-grid {
display: grid;
grid-template-columns:
repeat(
auto-fit,
minmax(
min(100%, 220px),
1fr
)
);
gap: 16px;
}
시작본과 이번 변경
HTML details와 summary로 접근 가능한 FAQ 만들기의 완료 체크포인트를 시작본으로 사용합니다.
index.html 기능 목록을 feature-grid로 바꾸고 요금제 pricing-grid를 추가합니다. style.css에 auto-fit/minmax 규칙을 적용하고 카드 1·2·4개에서 열 확장을 비교합니다.
연속 프로젝트 선수 조건
- Flexbox와 반응형 기본을 이해하고 있어야 합니다.
- 반복 카드가 여러 행으로 늘어날 때 Grid를 선택하는 기준을 다룹니다.
이전 체크포인트
publishing-step-05-faq
이번 목표
TaskFlow 기능 카드와 요금제 카드 구조를 Grid로 만듭니다.
Before / After
Before
feature cards가 Flex row 중심
After
카드 수가 늘어나도 Grid가 열과 행을 자동 구성
실행 확인
- 카드가 1개, 2개, 4개일 때 레이아웃을 확인합니다.
- 360px에서 카드가 viewport보다 넓어지지 않는지 봅니다.
- 넓은 화면에서 빈 공간이 과도하게 남지 않는지 확인합니다.
완료 체크포인트
publishing-step-06-grid
다음 학습
다음 글에서는 긴 URL과 긴 작업 제목 때문에 Flex/Grid가 넘치는 문제를 재현하고 min-width:0과 overflow-wrap으로 해결합니다.
글 소개·학습 준비·전체 목차

웹 퍼블리싱 · 6 / 15 · 필수 학습 · CSS Grid
Flexbox는 한 방향의 배치에 강하고 Grid는 행과 열을 함께 설계하는 2차원 레이아웃에 적합합니다.
이번 글에서는 TaskFlow 카드 목록을 Grid로 바꾸고 repeat(), minmax(), auto-fit을 이용해 카드 수와 화면 폭에 따라 자연스럽게 열이 조정되도록 만듭니다.
이번 글에서 배우는 내용
- display:grid
- grid-template-columns
- repeat()
- minmax()
- auto-fit
- auto-fill
- gap
- Flex와 Grid 선택 기준
먼저 알아야 할 내용
HTML 카드와 CSS 선택자·Flexbox의 한 방향 배치를 알면 됩니다. 독립 실습은 빈 폴더에서 시작합니다.
목차
이 글이 도움이 되었나요?
읽음 기록
읽음 — / 전체 15개 · 필수 13개
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.