repeat()의 횟수 자리에 auto-fill을, 값 자리에 minmax(260px, 1fr)을 쓰면 260px 이상인 열을 목록에 들어가는 만큼 만들고 남는 폭을 그 열끼리 나눕니다. 열 수를 숫자로 적지 않아, 목록 폭이 바뀌면 열 수가 저절로 세 열 · 두 열 · 한 열로 바뀝니다.
앞 레슨의 repeat(3, 1fr)은 창이 좁아져도 늘 세 열이라, 휴대전화에서는 카드가 비좁게 눌립니다. 카드 한 장이 읽을 만한 폭을 지키면서 열 수가 줄어들게 하려면, 열 수 자리에 숫자 대신 '들어가는 만큼'을 씁니다. 이 레슨은 이 값을 조각마다 읽고, 하위 목표 셋(1. 목록에 grid · 2. 열 최소 폭 · 3. 간격)으로 카드 격자를 씁니다.
그림 준비 중
1조각마다 읽기
.recipe-list {
display: grid;
grid-template-columns: repeat(
auto-fill,
minmax(260px, 1fr)
);
gap: 16px;
}
괄호가 두 겹이라 길어 보입니다. 안쪽부터 읽습니다.
| 조각 | 뜻 |
|---|---|
minmax(260px, 1fr) | 열 하나 — 가장 작게 260px, 가장 크게 1fr(남는 폭의 몫) |
auto-fill | 되풀이할 횟수 — 목록에 들어가는 만큼 |
repeat(…) | 그 열을 그 횟수만큼 되풀이 |
앞 레슨의 repeat(3, 1fr)에서 횟수 3 자리에 auto-fill이, 값 1fr 자리에 minmax(260px, 1fr)이 들어간 꼴입니다. 값이 길어 함수 괄호 안에서 줄을 나눴는데, 마지막 인자 뒤에는 쉼표를 붙이지 않습니다 — CSS는 끝 쉼표를 알아듣지 못해 선언을 통째로 버립니다.
2열 수 셈 — 목록 폭에 들어가는 만큼
<ul class="recipe-list">
<li>김치볶음밥</li>
<li>계란말이</li>
<li>된장찌개</li>
<li>떡볶이</li>
<li>잡채</li>
<li>미역국</li>
</ul>
.recipe-list {
display: grid;
grid-template-columns: repeat(
auto-fill,
minmax(260px, 1fr)
);
gap: 16px;
padding: 0;
list-style: none;
}944px.recipe-list의 너비928px.recipe-list의 열 수3.recipe-list li의 너비298.66px
창 944px에서 목록은 body 바깥 여백 둘을 뺀 928px입니다. 브라우저는 열 수부터 정합니다 — 열 n개에는 260 × n에 간격 n − 1개를 더한 폭이 있어야 합니다.
| 열 수 | 가장 작게 필요한 폭 |
|---|---|
| 1 | 260 |
| 2 | 260 × 2 + 16 = 536 |
| 3 | 260 × 3 + 16 × 2 = 812 |
| 4 | 260 × 4 + 16 × 3 = 1088 |
928px에는 812까지 들어가고 1088은 들지 않아 세 열입니다. 열 수가 정해지면 남는 폭을 1fr끼리 나눠 — (928 − 32) ÷ 3 — 열마다 약 298.7px로 260보다 넓어집니다.
창은 그대로 두고 목록의 폭만 줄여 봅니다.
.recipe-list {
width: 811px;
}944px.recipe-list의 열 수2.recipe-list li의 너비397.5px
.recipe-list {
width: 535px;
}944px.recipe-list의 열 수1.recipe-list li의 너비535px
812 · 536이 열 수가 바뀌는 경계입니다. 811px은 세 열에 1px 모자라 두 열이 되고, 남는 폭을 둘이 나눠 397.5px로 넓어집니다. 535px은 두 열에 1px 모자라 한 열이 그 폭을 다 씁니다. 경계와 경계 사이에서는 열 수는 그대로이고 열 너비만 늘고 줄어듭니다.
3열 수를 정하는 것은 목록이 놓인 폭
열 수를 정하는 것은 창 폭이 아니라 목록이 놓인 폭입니다. 목록이 body 바로 안이면 창 폭에서 16을 뺀 폭이라, 세 열이 되는 가장 좁은 창은 828px입니다.
<ul class="recipe-list">
<li>김치볶음밥</li>
<li>계란말이</li>
<li>된장찌개</li>
<li>떡볶이</li>
<li>잡채</li>
<li>미역국</li>
</ul>
.recipe-list {
display: grid;
grid-template-columns: repeat(
auto-fill,
minmax(260px, 1fr)
);
gap: 16px;
padding: 0;
list-style: none;
}828px.recipe-list의 열 수3.recipe-list li의 너비260px
창 828에서 목록 812 — 세 열이 꼭 들어가 열이 가장 작은 폭 260px 그대로입니다. 1px만 좁아져도 두 열이 됩니다.
예제
레시피 목록을 하위 목표 셋으로 씁니다.
<ul class="recipe-list">
<li>김치볶음밥</li>
<li>계란말이</li>
<li>된장찌개</li>
<li>떡볶이</li>
<li>잡채</li>
<li>미역국</li>
</ul>
.recipe-list {
/* 1. 목록에 grid */
display: grid;
padding: 0;
list-style: none;
/* 2. 열 최소 폭 */
grid-template-columns: repeat(
auto-fill,
minmax(260px, 1fr)
);
/* 3. 간격 */
gap: 16px;
}640px.recipe-list의 열 수2.recipe-list li의 너비304px
- 목록에 grid — 카드를 담은
ul에 줍니다. 카드 하나하나가 아닙니다(브라우저 규칙 7). 목록 점과 안쪽 여백도 여기서 지웁니다. - 열 최소 폭 — 카드 한 장이 읽을 만한 가장 좁은 폭(260px)만 정하고, 열 수는 브라우저에 맡깁니다.
- 간격 — 카드 사이는 카드마다의 바깥 여백이 아니라 부모의
gap하나로 띄웁니다. 열 사이와 줄 사이가 같은 16px입니다.
창 640px에서 목록은 624px — 두 열(536)은 들고 세 열(812)은 들지 않아 두 열, (624 − 16) ÷ 2 = 304px입니다.
자주 틀리는 곳
틀린 생각: 창이 넓으면 열이 많아진다.
넓은 화면에서 보면 카드가 여러 열로 놓일 것 같습니다.
<main>
<ul class="recipe-list">
<li>김치볶음밥</li>
<li>계란말이</li>
<li>된장찌개</li>
</ul>
</main>
main {
max-width: 520px;
margin: 0 auto;
}
.recipe-list {
display: grid;
grid-template-columns: repeat(
auto-fill,
minmax(260px, 1fr)
);
gap: 16px;
padding: 0;
}1280px.recipe-list의 너비520px.recipe-list의 열 수1
창은 1280px인데 카드가 한 줄에 하나씩입니다. 목록이 놓인 main이 520px까지만 넓어져, 두 열(536)도 들지 않았습니다.
맞는 규칙: 열 수는 목록이 놓인 부모의 폭으로 정해집니다. 520 안에 두 열을 놓으려면 가장 작은 폭을 (520 − 16) ÷ 2 = 252px 이하로 낮춥니다.
.recipe-list {
grid-template-columns: repeat(
auto-fill,
minmax(240px, 1fr)
);
}1280px.recipe-list의 열 수2.recipe-list li의 너비252px
틀린 생각: auto-fill과 auto-fit은 같다.
이름이 비슷하고, 카드가 많을 때는 결과도 같습니다.
<ul class="recipe-list">
<li>김치볶음밥</li>
<li>계란말이</li>
</ul>
.recipe-list {
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax(260px, 1fr)
);
gap: 16px;
padding: 0;
}944px.recipe-list li의 너비456px.recipe-list의grid-template-columns456px 456px 0px
목록 928px에 열은 셋 들어가지만 카드는 둘뿐입니다. auto-fit은 빈 셋째 열을 0으로 접어, 카드 둘이 남는 폭을 나눠 456px이 되었습니다. auto-fill이면 빈 셋째 열이 남아 카드 둘이 약 298.7px입니다.
맞는 규칙: 둘은 카드가 열보다 적을 때만 다릅니다 — auto-fill은 빈 열을 남기고, auto-fit은 빈 열을 접습니다. 카드 폭을 늘 같게 두려면 auto-fill입니다.
틀린 생각: minmax()의 두 값은 차례가 상관없다.
가장 작은 값과 가장 큰 값이니, 어느 쪽에 적어도 될 것 같습니다.
<ul class="recipe-list">
<li>김치볶음밥</li>
<li>계란말이</li>
</ul>
.recipe-list {
display: grid;
grid-template-columns: repeat(
auto-fill,
minmax(1fr, 260px)
);
padding: 0;
}.recipe-list의 grid-template-columns 선언(없음).recipe-list의 열 수1
선언이 통째로 버려져 카드가 한 열로 쌓였습니다. fr은 가장 크게 자리(뒤)에만 쓸 수 있어, 앞에 오면 알아듣지 못합니다(브라우저 규칙 4).
맞는 규칙: minmax(가장 작게, 가장 크게) — 앞이 가장 작은 폭, 뒤가 가장 큰 폭입니다.
확인 문제
1. 2절 예제(창 944)의 260px을 200px로 바꿨습니다. 열 수와 열 하나의 너비는 얼마일까요?
- (가) 열 수
- (나) 열 하나의 너비(px)
힌트
목록 폭 928에 200px 열이 몇 개까지 드는지, 간격까지 더해 셈합니다. 열 수가 정해지면 간격을 빼고 나눕니다.
정답
(가) 4 · (나) 220
<ul class="recipe-list">
<li>김치볶음밥</li>
<li>계란말이</li>
<li>된장찌개</li>
<li>떡볶이</li>
<li>잡채</li>
<li>미역국</li>
</ul>
.recipe-list {
display: grid;
grid-template-columns:
repeat(
auto-fill,
minmax(200px, 1fr)
);
gap: 16px;
padding: 0;
list-style: none;
}944px.recipe-list의 열 수4.recipe-list li의 너비220px
- 넷은 200 × 4 + 16 × 3 = 848로 들고, 다섯은 1064로 들지 않습니다. 남는 폭은 (928 − 48) ÷ 4 = 220px입니다.
- 232를 썼다면 간격을 빼지 않고 928을 넷으로 나눈 것입니다.
- 열 수 3을 썼다면 열의 가장 작은 폭이 줄어든 것을 셈에 넣지 않은 것입니다.
2. 카드 한 장이 200px보다 좁아지지 않고, 열 수는 목록 폭에 맡기는 열 선언을 쓰세요. 하위 목표 2를 통째로 채웁니다.
.recipe-list {
/* 1. 목록에 grid */
display: grid;
/* 2. 열 최소 폭 */
____
/* 3. 간격 */
gap: 16px;
}
힌트
열 하나의 가장 작은 폭과 가장 큰 폭을 정하는 함수, 그리고 횟수 자리에 '들어가는 만큼'을 쓰는 낱말을 떠올려 봅니다.
정답
.recipe-list {
/* 1. 목록에 grid */
display: grid;
/* 2. 열 최소 폭 */
grid-template-columns:
repeat(
auto-fill,
minmax(200px, 1fr)
);
/* 3. 간격 */
gap: 16px;
}auto-fit으로 써도 카드가 열보다 많으면 같은 화면입니다. 카드가 적을 때 폭이 달라집니다.- 한 줄로 쓰면 32칸을 넘어 함수 괄호 안에서 줄을 나눴습니다. 마지막 인자 뒤에는 쉼표를 붙이지 않습니다.
3. 여행 일정의 사진 칸을 폭 300px 상자 안에 놓았습니다. 결과 화면은 어떻게 될까요?
<ul class="trip">
<li>1일 바다</li>
<li>2일 시장</li>
</ul>
.trip {
display: grid;
grid-template-columns: repeat(
auto-fill,
minmax(320px, 1fr)
);
width: 300px;
padding: 0;
}
- ① 칸이 300px로 줄어 상자 안에 꼭 맞는다
- ② 칸이 320px 그대로라 상자 밖으로 넘친다
- ③ 열이 하나도 생기지 않아 칸이 그려지지 않는다
힌트
minmax()의 앞 값이 무엇을 정하는지, 그 값이 상자 폭보다 큰지 봅니다.
정답
② — 칸이 320px 그대로라 상자 밖으로 넘칩니다.
.trip li의 너비320px
- 한 열도 들지 않아도
auto-fill은 열을 하나 만들고, 그 열은 가장 작은 폭 320px 아래로 줄지 않습니다. 상자 300px 밖으로 20px 넘쳐, 휴대전화 화면에서 가로 스크롤이 생깁니다. - ①은
1fr이 늘 부모에 맞춰 준다고 본 것입니다.1fr은 가장 큰 폭이고, 가장 작은 폭은 앞 값입니다. auto-fill이 모든 폭의 넘침을 막아 주지는 않습니다 — 가장 작은 폭은 카드가 놓일 가장 좁은 부모보다 작게 정합니다.
컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요.
hello.html의 body 안을 예제 HTML로, style 요소 안의 규칙을 예제 CSS로 바꿔 저장 · 새로고침합니다. 창 폭을 천천히 줄이며 두 열이 한 열로 바뀌는 자리를 찾고, 개발자 도구 Elements 패널에서 ul 줄 끝의 grid 표시를 눌러 열 경계선을 봅니다. 260px을 200px로 바꾸면 경계가 목록 폭 536 · 812에서 416 · 632로 내려갑니다(200 × 2 + 16 · 200 × 3 + 32).