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 강좌 / width, height, min, max, box-sizing으로 크기 조절하기

CSS 강좌 / width, height, min, max, box-sizing으로 크기 조절하기

content-box와 border-box의 너비 계산, 최소·최대 크기, 고정 높이와 내용에 맞는 높이를 비교합니다. 화면과 글자 크기를 바꾸며 넘침을 진단하고 백분율 높이의 조건을 확인합니다.

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

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

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

CSS 강좌 / Flexbox로 요소를 한 방향에 배치하기

CSS 강좌 / Flexbox로 요소를 한 방향에 배치하기

Flexbox의 직접 자식, 주축과 교차축, row·column·reverse의 차이를 전체 예제로 익힙니다. 초기 크기와 키보드 순서를 비교하면서 배치가 달라지는 이유를 확인합니다.

CSS / Tutorial / 구분선 만드는 방법

CSS / Tutorial / 구분선 만드는 방법

글의 완급 조절, 내용 전환 등을 위해 구분선을 사용하는 경우가 많습니다. 선은 여러 가지 방식으로 만들 수 있는데, 보기 좋게 꾸미는 것은 CSS로 합니다. 아래는 div 태그에 모양을 입혀서 구분선을 만드는 몇 가지 예제입니다.

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

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

repeat·auto-fit·auto-fill의 차이와 자동 배치 순서를 실행 예제로 비교합니다. grid-template-areas로 페이지를 구성하고 모바일 전환, 영역 이름 오류와 읽기 순서도 확인합니다.

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

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

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

CSS / Tutorial / ul, ol 가운데 정렬하는 방법

CSS / Tutorial / ul, ol 가운데 정렬하는 방법

목록 자체가 아니라 목록 안의 내용만 가운데 정렬할 때는 text-align 속성을 사용합니다. 목록 요소 자체를 가운데 정렬할 때는 margin 속성을 사용합니다. 만약 요소의 내용에 맞게 자동으로 크기가 정해지게 하고 싶으면 display 속성을 사용합니다.

CSS / Tutorial / 원 또는 타원 만드는 방법

CSS / Tutorial / 원 또는 타원 만드는 방법

CSS의 border-radius 속성으로 원 또는 타원을 만들 수 있습니다. HTML 문서에 다음과 같이 내용이 없는 요소를 하나 만듭니다. 적절히 크기를 정하여 정사각형을 만들고, 배경색을 넣습니다. border-radius 속성을 추가하고, 값에 50%를 넣으면 원이 만들어집니다.

CSS 강좌 / 문법

CSS 강좌 / 문법

CSS의 선택자·선언·구분 기호·주석을 예제로 설명합니다. 잘못된 속성값과 세미콜론 누락을 비교하고, 실행 가능한 예제와 오류 수정 실습으로 브라우저가 적용한 결과를 확인합니다.

CSS / Tutorial / 마름모 만드는 방법

CSS / Tutorial / 마름모 만드는 방법

CSS로 삼각형을 만들 수 있다면 마름모는 쉽게 만들 수 있습니다. 삼각형을 두 개 붙이면 마름모가 되기 때문입니다. 마름모는 네 변의 길이가 같은 사각형이므로, 이등변삼각형 두 개를 붙이며 됩니다.