grid-template-columns는 격자의 열을 정하는 CSS 속성입니다. 빈칸으로 늘어놓은 값 하나가 열 하나이고, fr은 간격을 뺀 남는 폭을 몇 몫씩 받을지 정합니다.
앞 레슨에서 repeat(4, 1fr)을 읽는 법 없이 썼습니다. 열 너비를 px로 정하면 부모 폭이 바뀔 때 남거나 넘치고, %로 나누면 간격만큼 넘칩니다. 이 레슨은 열 값을 읽는 법과 열 하나의 너비를 셈하는 법을 봅니다.
그림 준비 중
1값 하나가 열 하나
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
.grid {
display: grid;
grid-template-columns:
80px 80px 80px;
gap: 16px;
width: 300px;
}
.grid div {
background-color: #d2d2d7;
}.grid의 열 수3.grid의 줄 수2.grid div의 너비80px
빈칸으로 가른 값이 셋이라 열이 셋입니다. 줄은 따로 정하지 않았습니다 — 열 셋을 채우고 남은 항목은 브라우저가 다음 줄을 만들어 놓습니다. gap은 열 사이와 줄 사이를 함께 띄웁니다(12단원 flex의 gap과 같은 속성).
열 셋과 간격 둘을 더하면 80 × 3 + 16 × 2 = 272px이라, 부모 300px 안에서 오른쪽 28px이 빕니다. px로 정한 열은 부모 폭과 상관없이 그 너비 그대로입니다 — 부모가 더 좁으면 밖으로 넘칩니다.
2fr은 간격을 뺀 남는 폭의 몫
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
.grid {
display: grid;
grid-template-columns:
1fr 1fr 1fr;
gap: 16px;
width: 300px;
}
.grid div {
background-color: #d2d2d7;
}.grid div의 너비89.33px.grid div:nth-child(3)의 오른쪽 끝308px
fr은 남는 폭을 몇 몫 받을지 적는 단위입니다(fraction — 몫). 브라우저는 간격 둘(32px)을 먼저 빼고, 남은 268px을 몫의 합 3으로 나눕니다. 열 하나가 89.33px이고, 셋째 열의 오른쪽 끝이 부모 끝(8 + 300)에 꼭 맞습니다.
몫이 다르거나 px 열이 섞여도 셈하는 차례는 같습니다 — 간격과 px 열을 먼저 빼고, 남은 폭을 몫대로 나눕니다.
| 값(부모 300 · 간격 16) | 셈 | 열 너비 |
|---|---|---|
1fr 1fr 1fr | (300 − 32) ÷ 3 | 89.33 · 89.33 · 89.33 |
2fr 1fr | (300 − 16) ÷ 3이 한 몫 | 약 189.3 · 94.7 |
100px 1fr | 300 − 16 − 100 | 100 · 184 |
3같은 값은 repeat()로
같은 값을 여러 번 적는 대신 repeat()로 되풀이할 수 있습니다. 괄호 안에 횟수, 쉼표, 되풀이할 값을 씁니다.
| 늘어놓아 쓰기 | repeat()로 쓰기 |
|---|---|
1fr 1fr 1fr | repeat(3, 1fr) |
80px 80px 80px | repeat(3, 80px) |
1fr 1fr 1fr 1fr | repeat(4, 1fr) |
열 값끼리는 빈칸으로 가르고, 쉼표는 repeat() 안의 횟수와 값 사이에만 씁니다.
4긴 글자는 fr 열도 넓힌다
첫 칸에 빈칸 없는 긴 주소가 들어 있습니다.
<div class="grid">
<div>
https://example.com/kimchi
</div>
<div>2</div>
<div>3</div>
</div>
.grid {
display: grid;
grid-template-columns:
repeat(3, 1fr);
gap: 16px;
width: 300px;
}
.grid div {
background-color: #d2d2d7;
}.grid div의min-widthauto
첫 열만 넓어지고 나머지 두 열은 좁아졌습니다. 격자 항목의 min-width 처음 값 auto는 내용이 줄을 바꿀 수 있는 가장 작은 폭을 지킵니다. 빈칸 없는 주소는 바꿀 자리가 없어, 1fr 열이 그만큼 넓어졌습니다.
열의 가장 작은 폭을 0으로 정하면 세 열이 다시 같은 폭이 됩니다. minmax(0, 1fr)은 '가장 작게 0, 가장 크게 1fr'인 열입니다 — minmax()는 다음 레슨에서 자세히 봅니다.
.grid {
grid-template-columns:
repeat(3, minmax(0, 1fr));
}.grid div의 너비89.33px.grid div:nth-child(2)의 너비89.33px
다만 주소 글자는 줄을 바꾸지 못해 칸 밖으로 삐져나와, 옆 칸 밑에 가려집니다. 열이 커지는 일과 칸 안 글자가 넘치는 일은 따로입니다 — 긴 글자를 칸 안에서 꺾는 법은 12단원 gap과 flex: 1과 같습니다(overflow-wrap: anywhere).
예제
목록 폭 280px에 레시피 카드 여섯 장을 두 열로 놓습니다. 결과 화면을 펴기 전에, 카드가 몇 줄이 되고 카드 하나의 너비가 몇 px일지 셈해 보세요.
<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(2, 1fr);
gap: 16px;
width: 280px;
padding: 0;
list-style: none;
}
.recipe-list li {
background-color: #d2d2d7;
}
결과 화면 보기
.recipe-list의 열 수2.recipe-list의 줄 수3.recipe-list li의 너비132px
열이 둘이고 카드가 여섯이라 세 줄입니다. 간격은 두 열 사이 한 곳뿐이라 (280 − 16) ÷ 2 = 132px입니다. 카드는 HTML 차례대로 칸을 채웁니다 — 김치볶음밥 · 계란말이가 첫 줄, 된장찌개 · 떡볶이가 둘째 줄, 잡채 · 미역국이 셋째 줄입니다.
자주 틀리는 곳
틀린 생각: 33.33% 세 열이면 부모에 꼭 맞는다.
33.33%씩 세 번이면 거의 100%라 꼭 맞을 것 같습니다.
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
.grid {
display: grid;
grid-template-columns:
33.33% 33.33% 33.33%;
gap: 16px;
width: 300px;
}
.grid div {
background-color: #d2d2d7;
}.grid div:nth-child(3)의 오른쪽 끝339.95px
세 열이 부모 폭을 거의 다 쓴 데다 간격 32px이 더해져, 셋째 열이 부모 끝(308px)을 넘어 339.95px까지 나갔습니다. 휴대전화 화면에서는 가로 스크롤이 생깁니다.
맞는 규칙: %는 부모 폭의 몫이라 간격을 빼지 않습니다. 간격을 뺀 남는 폭을 나누려면 fr을 씁니다.
틀린 생각: fr은 부모 폭 전체를 나눈다.
열 넷이 1fr씩이면 300 ÷ 4 = 75px일 것 같습니다.
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
.grid {
display: grid;
grid-template-columns:
repeat(4, 1fr);
gap: 20px;
width: 300px;
}.grid div의 너비60px
간격 셋(60px)을 먼저 빼고 남은 240px을 넷이 나눠 60px입니다.
맞는 규칙: fr은 간격과 px 열을 뺀 남는 폭의 몫입니다.
틀린 생각: repeat() 안에서도 값을 빈칸으로 가른다.
열 값을 빈칸으로 가르니, repeat() 안도 빈칸으로 쓰면 될 것 같습니다.
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
.grid {
display: grid;
grid-template-columns:
repeat(3 1fr);
}.grid의 grid-template-columns 선언(없음).grid의 열 수1
쉼표가 빠진 repeat()를 알아듣지 못해 선언을 통째로 버렸습니다. 열을 정하지 않은 격자라 셋이 한 열로 쌓였고, 오류 메시지는 없습니다.
맞는 규칙: repeat() 안은 '횟수, 값' — 쉼표가 있어야 합니다. 알아듣지 못한 선언은 오류 없이 버려집니다(브라우저 규칙 4). Styles 창에서 그 선언에 경고 표시와 취소선이 보입니다.
틀린 생각: 칸에 놓일 상자에 열 수를 정한다.
상자가 세 열로 놓이길 바라니, 상자 규칙에 grid-template-columns를 쓸 것 같습니다.
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
.grid {
display: grid;
}
.grid div {
grid-template-columns:
repeat(3, 1fr);
}.grid의 열 수1
상자의 grid-template-columns는 상자 자신이 격자일 때만 쓰입니다. 부모 .grid에는 열이 없어 한 열입니다.
맞는 규칙: 열은 격자가 된 부모가 정하고, 자식은 그 칸에 놓입니다(브라우저 규칙 7).
확인 문제
1. 예제의 repeat(2, 1fr)을 1fr 3fr로 바꿨습니다. 계란말이 카드의 너비는 몇 px일까요?
<ul class="recipe-list">
<li>김치볶음밥</li>
<li>계란말이</li>
<li>된장찌개</li>
<li>떡볶이</li>
<li>잡채</li>
<li>미역국</li>
</ul>
.recipe-list {
display: grid;
grid-template-columns:
1fr 3fr;
gap: 16px;
width: 280px;
padding: 0;
list-style: none;
}
.recipe-list li {
background-color: #d2d2d7;
}
힌트
계란말이가 몇째 열에 놓이는지 보고, 간격을 뺀 남는 폭을 몫의 합으로 나눠 봅니다.
정답
받는 답: 198
.recipe-list li:nth-child(2)의 너비198px.recipe-list li의 너비66px
- 간격 한 곳을 빼면 264px, 몫의 합은 1 + 3 = 4라 한 몫이 66px입니다. 계란말이는 둘째 열이라 세 몫, 198px입니다.
- 210을 썼다면 간격을 빼지 않고 280을 넷으로 나눈 것입니다.
- 132를 썼다면 열 값이 바뀐 것을 놓친 것입니다.
2. 긴 주소가 든 카드가 있어도 세 열이 같은 폭을 지키게 하려 합니다. 주석은 카드 격자를 짜는 하위 목표 셋입니다(셋은 다음 레슨 들어가는 만큼 열 만들기에서 정리합니다). ____ 자리에 알맞은 값을 쓰세요.
.recipe-list {
/* 1. 목록에 grid */
display: grid;
/* 2. 열 최소 폭 */
grid-template-columns:
repeat(3, ____);
/* 3. 간격 */
gap: 16px;
}
힌트
4절에서 주소가 든 열이 넓어진 뒤, 세 열을 다시 같은 폭으로 만든 코드를 찾아보세요.
힌트 둘
1fr 열이 넓어진 까닭은 열의 가장 작은 폭이었습니다. 그 가장 작은 폭을 열 값 안에서 정하는 꼴을 떠올려 봅니다.
정답
minmax(0, 1fr)
.recipe-list {
/* 1. 목록에 grid */
display: grid;
/* 2. 열 최소 폭 */
grid-template-columns:
repeat(
3,
minmax(0, 1fr)
);
/* 3. 간격 */
gap: 16px;
}가장 작은 폭을 0으로 정한 열이라, 긴 주소가 들어도 세 열이 남는 폭을 같은 몫으로 나눕니다. 1fr만 쓰면 주소가 든 열이 넓어집니다.
3. 동아리 공지 카드 셋을 세 열로 놓으려 했는데, 셋이 한 열로 쌓였습니다. 어느 줄을 어떻게 고치면 될까요? 고친 줄을 쓰세요.
<div class="notices">
<p>모임 공지</p>
<p>회비 안내</p>
<p>사진 모음</p>
</div>
.notices {
display: grid;
grid-template-columns:
1fr, 1fr, 1fr;
gap: 16px;
}힌트
Styles 창에서 .notices 규칙의 선언마다 경고 표시가 있는지 봅니다.
정답
받는 답: 1fr 1fr 1fr 또는 repeat(3, 1fr) — 3 · 4번 줄의 값
.notices {
display: grid;
grid-template-columns:
1fr 1fr 1fr;
gap: 16px;
}.notices의 열 수3
- 열 값 사이에 쉼표를 넣어 선언째 버려졌습니다(브라우저 규칙 4). 열 값끼리는 빈칸으로 가릅니다.
- 쉼표는
repeat(3, 1fr)처럼repeat()안의 횟수와 값 사이에만 씁니다. - 찾는 차례 4번(닿았으면 알아들었나)에서 찾습니다 — Styles 창에 그 선언이 경고 표시와 취소선으로 보입니다.
컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요.
hello.html의 body 안을 2절 HTML로, style 요소 안의 규칙을 2절 CSS로 바꿔 저장 · 새로고침합니다. 개발자 도구 Elements 패널에서 .grid 줄을 고르고 Computed 창에서 grid-template-columns를 찾으면, 1fr이 px로 풀린 열 너비 셋이 보입니다. gap을 0으로 바꾸면 열 셋이 100px씩이 됩니다.