AD JB Toolbox 01

CSS 강좌 / Grid 반복 열·자동 배치·영역 이름 사용하기

Grid의 repeat()는 같은 열 정의를 반복하고, auto-fit과 auto-fill은 컨테이너에 들어갈 열 수를 자동으로 정합니다. 이름으로 큰 구역을 배치하려면 grid-template-areas를 사용하며, 자동 배치와 영역 이름은 서로 다른 문제를 해결하는 기능입니다.

고정 반복과 자동 반복을 구분하기

.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

repeat(3, ...)는 화면 크기와 관계없이 세 열을 정의합니다. 같은 선언을 세 번 쓰는 것과 의미가 같습니다. 항목 수가 네 개이면 세 열을 유지하면서 다음 행에 네 번째 항목이 들어갑니다. 카드 수에 맞춰 열 수도 네 개로 늘어난다는 뜻은 아닙니다.

.cards {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 192px), 1fr));
}

auto-fit은 지정한 최소 크기의 열이 몇 개 들어갈지 계산합니다. minmax의 첫 값은 최소, 둘째 값은 최대이며 1fr은 남는 공간을 나누어 갖게 합니다. 여기서 min(100%, 192px)는 최소 열 너비가 부모보다 커지지 않도록 합니다. 열의 최소값을 192px로만 고정하면 부모가 192px보다 좁을 때 한 열조차 부모 밖으로 넘칠 수 있습니다.

예를 들어 800px 컨테이너에서 최소 192px 열과 16px gap을 사용하면 세 열과 두 gap은 608px, 네 열과 세 gap은 816px입니다. 따라서 세 열까지 들어갈 수 있습니다. 이것은 열의 수를 결정하는 단계이고, 이후 실제 열 너비는 남는 공간을 분배하는 단계에서 달라집니다. 카드에 긴 문자열이 있으면 열 수와 별개로 줄바꿈 규칙도 확인해야 합니다.

auto-fill과 auto-fit을 적은 항목으로 비교하기

값 아이템 배치 후 빈 반복 트랙 항목이 적은 넓은 화면
auto-fill 빈 열도 유지 빈 열의 공간이 남음
auto-fit 아이템이 없는 반복 트랙을 접음 사용 중인 열이 남는 공간을 더 채움

두 값 모두 처음에는 들어갈 수 있는 반복 열을 계산합니다. auto-fit의 차이는 배치 후 비어 있는 반복 트랙을 접는 과정에 있습니다. 항목이 모든 열을 채우면 두 값이 비슷하게 보일 수 있으므로 비교할 때는 컨테이너를 넓게 만들고 카드 수를 적게 두세요. 모든 카드가 작은 화면 한 열에 들어가는 조건에서도 차이가 잘 보이지 않습니다. MDN의 repeat() 설명에서 자동 반복 규칙을 확인할 수 있습니다.

자동 배치와 dense의 순서 문제 이해하기

위치를 지정하지 않은 아이템은 기본 grid-auto-flow: row에 따라 행 방향으로 배치됩니다. 앞의 아이템이 넓은 영역을 차지해 빈 칸이 생기더라도 기본 배치는 다음 아이템을 배치하면서 지나간 빈 칸으로 계속 되돌아가지 않습니다. 이 기본 동작은 HTML 순서와 시각적인 진행을 이해하기 쉽게 만듭니다.

grid-auto-flow: row dense는 뒤의 작은 아이템을 앞의 빈 칸에 채울 수 있습니다. 공간은 촘촘해지지만 화면에서 보이는 순서와 DOM(Document Object Model)의 순서가 달라질 수 있습니다. CSS 배치는 HTML을 재정렬하지 않으므로 키보드 포커스와 읽기 순서를 함께 검토해야 합니다. 번호가 의미 있는 단계, 시간순 기록, 양식 항목에서는 빈 칸을 없애는 것보다 순서를 지키는 것이 우선입니다. MDN의 grid-auto-flow 설명에서 자동 배치 조건을 확인할 수 있습니다.

전체 예제로 반복 열과 자동 배치 실습하기

아래 코드를 grid-auto-repeat.html로 저장해 엽니다. 첫 구역에는 카드가 두 개뿐이고 컨테이너 최대 너비는 800px입니다. 둘째 구역은 두 칸짜리 링크 두 개와 한 칸짜리 링크 두 개로 빈 칸을 만들었습니다.

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>grid-auto-repeat.html</title>
  <style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 192px), 1fr));
 gap: 16px; width: min(100%, 800px); }
 .cards > div { min-width: 0; padding: 16px; background: #dceefa; overflow-wrap: anywhere; }
 .flow { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px;
 grid-auto-flow: row; max-width: 600px; margin-top: 16px; }
 .flow > a { padding: 12px; background: #e8f5de; }
 .flow > .wide { grid-column: span 2; }
  </style>
</head>
<body>
<h1>빈 반복 열 비교</h1><div class="cards"><div>첫 카드</div><div>둘째 카드</div></div>
<h2>기본 자동 배치</h2><div class="flow"><a class="wide" href="#result">1: 두 칸</a><a class="wide" href="#result">2: 두 칸</a><a href="#result">3: 한 칸</a><a href="#result">4: 한 칸</a></div>
<p id="result">자동 배치 링크의 이동 대상입니다.</p>
</body>
</html>
  1. 넓은 화면에서 첫 구역이 800px이면 auto-fit의 두 카드가 각각 392px를 차지합니다. auto-fit만 auto-fill로 바꾸면 세 열이 유지되어 첫 두 열의 카드는 약 256px이고 빈 열이 남습니다. 확인 후 auto-fit으로 복원합니다.
  2. 첫 구역에 div를 더 복사해 네 개로 만듭니다. 세 열이 채워지고 네 번째 카드가 다음 행에 놓입니다. 이 조건에서는 비어 있는 반복 열이 없어 두 값의 차이가 줄어듭니다. 실습 후 원래 두 카드로 돌립니다.
  3. 화면을 좁혀 부모 너비가 192px보다 작아지도록 확인합니다. min(100%, 192px) 덕분에 한 열이 부모에 맞습니다. 최소값을 192px로만 바꾸면 더 좁은 영역에서 넘칠 수 있습니다. 비교 후 원래 식을 복원합니다.
  4. .flow에서 1번 링크 뒤의 빈 칸과 3번 링크 위치를 확인합니다. grid-auto-flow만 row dense로 바꾸면 3번이 앞의 빈 칸에 올라갑니다. Tab으로는 1 → 2 → 3 → 4 순서가 유지되는지 확인합니다. 실습 후 row로 되돌립니다.

영역 이름으로 페이지 구조 만들기

열·행 번호를 각각 계산하기보다 header·main·aside·footer 같은 이름으로 큰 구역을 표현하면 페이지의 배치 의도를 읽기 쉽습니다. grid-template-areas의 각 문자열은 한 행이고, 문자열 안의 공백으로 구분한 이름은 셀입니다. 자식의 grid-area 값이 그 이름과 일치해야 해당 영역에 들어갑니다.

같은 이름을 여러 셀에 반복하면 하나의 직사각형 영역을 만듭니다. 영역은 L자나 떨어진 섬 모양으로 지정할 수 없습니다. 각 행은 같은 셀 수를 가져야 하고 비워 둘 셀은 점(.)으로 표시합니다. 선언이 유효하지 않으면 브라우저가 해당 선언을 적용하지 않아 자동 배치처럼 보일 수 있습니다. MDN의 grid-template-areas 설명에서 유효한 영역 조건을 확인할 수 있습니다.

아래 코드는 grid-areas.html로 저장합니다. 데스크톱에서는 본문과 보조 정보가 옆으로 놓이고 640px 이하에서는 한 열로 바뀝니다. 화면 배치에 맞추어 HTML 순서를 뒤집지 않고 본문이 보조 정보보다 앞에 오도록 구성했습니다.

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>grid-areas.html</title>
  <style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
.page { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
 grid-template-areas: "header header" "main aside" "footer footer"; gap: 16px; max-width: 1000px; }
 .page > * { min-width: 0; padding: 20px; background: #dceefa; overflow-wrap: anywhere; }
 header { grid-area: header; } main { grid-area: main; } aside { grid-area: aside; } footer { grid-area: footer; }
 @media (max-width: 640px) {
 .page { grid-template-columns: minmax(0, 1fr); grid-template-areas: "header" "main" "aside" "footer"; }
 }
  </style>
</head>
<body>
<h1>페이지 영역 이름</h1><div class="page"><header>사이트 제목</header><main><h2>주요 콘텐츠</h2><p>본문 영역입니다. 모바일에서도 본문이 먼저 나오도록 HTML 순서를 구성했습니다.</p></main><aside>관련 정보</aside><footer>연락처와 사이트 안내</footer></div>
</body>
</html>
  1. 넓은 화면에서 header와 footer가 두 열을 차지하는지 확인합니다. 화면을 640px 이하로 좁히면 header → main → aside → footer가 한 열로 이어집니다. 열 정의와 영역 문자열을 함께 바꿔야 하는 이유를 확인하세요.
  2. aside의 grid-area만 다른 이름으로 바꿉니다. 템플릿에서 예약한 aside 영역과 실제 요소의 연결이 끊겨 의도한 칸에 놓이지 않을 수 있습니다. 이름을 aside로 복원합니다.
  3. 넓은 화면 템플릿만 "header header" "header aside" "footer footer"로 바꾸면 header가 L자라 해당 grid-template-areas 선언이 유효하지 않습니다. 개발자 도구에서 적용 여부를 확인한 뒤 원래 세 문자열을 복원합니다.

실무에서는 카드 수에 따라 열을 만드는 영역과 페이지 구역 이름을 지정하는 영역을 분리하면 관리하기 쉽습니다. 자동 반복은 개수와 최소 너비를, 영역 이름은 페이지 구조와 전환점을 결정합니다. 둘을 한 규칙에 억지로 섞기 전에 각 컨테이너가 해결하려는 문제가 무엇인지 먼저 정하세요.

같은 카테고리의 다른 글
CSS / Tutorial / 유튜브 동영상을 반응형으로 삽입하는 방법

CSS / Tutorial / 유튜브 동영상을 반응형으로 삽입하는 방법

유튜브 영상을 블로그나 홈페이지에 넣을 때 보통 iframe을 사용합니다. 코드는 유튜브 영상 공유에서 를 클릭하여 구할 수 있습니다. 아래와 같은 코드인데, 고정폭입니다. 즉 웹브라우저의 가로폭이 커지든 작아지든 가로폭이 일정합니다. 이를 반응형으로 만들고 싶다면 아래처럼 합니다.

CSS 강좌 / 링크 꾸미는 방법

CSS 강좌 / 링크 꾸미는 방법

링크의 기본 밑줄과 방문·호버·활성 상태를 설정하고 키보드 포커스를 표시합니다. 두 파일로 방문 이력과 Tab·Enter 동작을 확인하며 상태 규칙이 겹칠 때의 결과를 설명합니다.

CSS 강좌 / position의 relative·absolute·fixed·sticky 차이

CSS 강좌 / position의 relative·absolute·fixed·sticky 차이

relative·absolute·fixed·sticky의 공간 유지, 위치 기준과 스크롤 차이를 비교합니다. 배지와 고정 버튼, 붙는 제목 예제를 실행하며 기준 부모와 동작하지 않는 원인을 확인합니다.

CSS / Tutorial / 삼각형 만드는 방법

CSS / Tutorial / 삼각형 만드는 방법

CSS의 border 속성으로 삼각형을 만들 수 있습니다. 여러 형태의 삼각형을 만들고, 그 삼각형을 회전하는 방법을 알아봅니다.

CSS 강좌 / Flexbox 정렬·간격·줄바꿈·크기 조절하기

CSS 강좌 / Flexbox 정렬·간격·줄바꿈·크기 조절하기

Flexbox의 아이템 정렬과 여러 줄 정렬을 구분하고, gap·줄바꿈·grow·shrink·basis를 비교 예제로 익힙니다. 긴 문자열이 넘치는 원인과 크기·줄바꿈의 해결 방법도 다룹니다.

CSS 강좌 / CSS란 무엇이고 HTML과 어떻게 다를까?

CSS 강좌 / CSS란 무엇이고 HTML과 어떻게 다를까?

HTML과 CSS의 역할을 구분하고, 같은 작은 정원 문서에 색상·배경·여백을 적용합니다. 실행 가능한 예제와 세 가지 변형 실습으로 스타일이 바뀌는 범위를 확인할 수 있습니다.

CSS 강좌 / 색상 값과 px·em·rem·% 단위 이해하기

CSS 강좌 / 색상 값과 px·em·rem·% 단위 이해하기

색상 표기와 px·em·rem·%의 계산 기준을 비교합니다. 중첩된 글자 크기와 여백이 있는 상자 예제로 실제 크기를 계산하고 개발자 도구에서 확인할 수 있습니다.

CSS 강좌 / 문단과 목록의 간격, 정렬, 목록 표시 설정하기

CSS 강좌 / 문단과 목록의 간격, 정렬, 목록 표시 설정하기

문단 안의 줄 간격, 문단 사이 여백, 첫 줄 들여쓰기를 구분합니다. 긴 목록을 이용해 outside·inside 표시 위치와 항목 간격을 비교하고 정렬 문제를 확인할 수 있습니다.

CSS 강좌 / 미디어 쿼리와 콘텐츠 기준 분기점 만들기

CSS 강좌 / 미디어 쿼리와 콘텐츠 기준 분기점 만들기

카드의 최소 폭과 여백을 기준으로 미디어 쿼리 분기점을 정합니다. 1·2·3열 전체 예제와 경계값 비교로 조건이 적용되는 과정을 확인합니다.

CSS 강좌 / z-index와 쌓임 맥락 이해하기

CSS 강좌 / z-index와 쌓임 맥락 이해하기

z-index의 적용 조건과 부모 쌓임 맥락을 실제로 겹치는 예제로 이해합니다. 자식과 부모의 숫자 변경을 비교하고, overflow 잘림과 겹침 순서를 구분해 문제를 해결합니다.