본문으로 건너뛰기

열 만들기

HTML·CSS 목차격자로 배치: grid레슨 72 / 93

목차

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) ÷ 389.33 · 89.33 · 89.33
2fr 1fr(300 − 16) ÷ 3이 한 몫약 189.3 · 94.7
100px 1fr300 − 16 − 100100 · 184

3같은 값은 repeat()로

같은 값을 여러 번 적는 대신 repeat()로 되풀이할 수 있습니다. 괄호 안에 횟수, 쉼표, 되풀이할 값을 씁니다.

늘어놓아 쓰기repeat()로 쓰기
1fr 1fr 1frrepeat(3, 1fr)
80px 80px 80pxrepeat(3, 80px)
1fr 1fr 1fr 1frrepeat(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씩이 됩니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

HTML·CSS 목차로