본문으로 건너뛰기

들어가는 만큼 열 만들기

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

목차

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개를 더한 폭이 있어야 합니다.

열 수가장 작게 필요한 폭
1260
2260 × 2 + 16 = 536
3260 × 3 + 16 × 2 = 812
4260 × 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
  1. 목록에 grid — 카드를 담은 ul에 줍니다. 카드 하나하나가 아닙니다(브라우저 규칙 7). 목록 점과 안쪽 여백도 여기서 지웁니다.
  2. 열 최소 폭 — 카드 한 장이 읽을 만한 가장 좁은 폭(260px)만 정하고, 열 수는 브라우저에 맡깁니다.
  3. 간격 — 카드 사이는 카드마다의 바깥 여백이 아니라 부모의 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).

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

HTML·CSS 목차로