이번 편의 결과물: 06편의 카드 그리드 안에서 각 카드 내부(제목·설명·버튼)의 줄이 카드마다 흔들리지 않고 서브그리드로 나란히 맞춰집니다. 다루는 개념: grid-template-columns/rows: subgrid, 부모 트랙 상속 이유, 제목·설명·버튼 줄맞춤
이 편에서 만드는 파일
web-practice/portfolio/
└─ css/styles.css ~ (project-grid에 서브그리드 행 추가)
web-practice/lessons/modern-css/
└─ 08_subgrid-card-alignment/ + (이번 편 스냅샷)
└─ notes.md개념 정리
06편에서 .project-grid를 그리드로, .project-card를 그 안의 그리드 아이템으로 만들었습니다. 문제는 카드 각각이 독립된 그리드라, 카드 1의 설명이 3줄이고 카드 2의 설명이 1줄이면 두 카드의 버튼 위치가 서로 어긋난다는 점입니다.
서브그리드는 자식 그리드가 자신만의 트랙을 새로 만들지 않고, 부모 그리드의 트랙을 그대로 물려받게 합니다.
| 값 | 뜻 |
|---|---|
grid-template-columns: subgrid | 자신의 열 트랙을 부모의 열 트랙 그대로 상속 |
grid-template-rows: subgrid | 자신의 행 트랙을 부모의 행 트랙 그대로 상속 |
| 전제 조건 | 이 값을 쓰는 요소 자신이 부모 그리드의 그리드 아이템이어야 하고, grid-column/grid-row로 몇 개 트랙에 걸치는지 지정돼 있어야 함 |
부모가 “제목 행 · 설명 행 · 버튼 행” 세 종류의 행 트랙을 정의해 두면, 서브그리드로 상속받은 카드들은 같은 이름의 행에 내용이 몇 줄이든 그 행의 높이가 카드 전체 중 가장 큰 값으로 맞춰집니다. 이것이 부모 트랙을 상속해야 하는 이유입니다 — 각자 다른 그리드였다면 이 정렬이 카드마다 따로 계산되어 절대 맞을 수 없습니다.
흔한 오해: display: grid만 걸면 자동으로 부모와 정렬될 거라 생각하기 쉽지만, subgrid 값을 명시하지 않으면 자식은 완전히 새로운 독립 그리드를 만듭니다. 부모와 트랙을 공유하려면 반드시 subgrid라고 써야 합니다.
실습
1. 부모 그리드에 행 트랙 이름 정의하기
/* portfolio/css/styles.css */
@layer components {
.project-grid {
container-type: inline-size;
container-name: cards;
display: grid;
grid-template-columns: 1fr;
grid-auto-rows: auto;
gap: var(--space-6);
}
@container cards (min-width: 480px) {
.project-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@container cards (min-width: 768px) {
.project-grid {
grid-template-columns: repeat(3, 1fr);
}
}
}카드 내부 행을 부모가 통제하려면, 카드 각각이 부모 그리드 안에서 몇 개의 행에 걸쳐 있는지부터 정해야 합니다. 다음 단계에서 부모에 명시적인 행 트랙 3개(제목·설명·버튼)를 만듭니다.
2. 카드를 서브그리드로 만들기
/* portfolio/css/styles.css */
@layer components {
.project-grid {
/* 카드 한 장당 제목·설명·버튼 3행을 명시적으로 정의 */
grid-template-rows: auto 1fr auto;
grid-auto-flow: row;
}
.project-card {
/* 이 카드가 부모의 행 트랙 3칸을 그대로 씀 */
display: grid;
grid-row: span 3;
grid-template-rows: subgrid;
gap: var(--space-2);
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius);
padding: var(--space-4);
}
}grid-row: span 3이 “이 카드는 부모의 행 트랙 3칸을 차지한다”는 뜻이고, grid-template-rows: subgrid가 “그 3칸을 내 자식(제목·설명·버튼)에게 그대로 물려준다”는 뜻입니다. 두 선언이 함께 있어야 서브그리드가 성립합니다.
3. 카드 내부 요소를 각 행에 배치하기
/* portfolio/css/styles.css */
@layer components {
.project-card h2 {
grid-row: 1;
font-size: clamp(1rem, 6cqi, 1.375rem);
}
.project-card p {
grid-row: 2;
color: var(--color-text-muted);
}
.project-card button[data-open-project] {
grid-row: 3;
align-self: end;
}
}grid-row: 1, 2, 3은 서브그리드가 상속한 부모의 행 번호를 그대로 가리킵니다. 07편에서 만든 @scope (.project-card) to (button[data-open-project]) 블록 안에 있는 h2·p·button[data-open-project] 규칙에 이 행 번호를 덧붙이는 것도 같은 효과를 냅니다 — 여기서는 .project-card 후손 선택자로 적어 두 편의 코드를 독립적으로 확인할 수 있게 했습니다. 이제 카드마다 설명 줄 수가 달라도, 2행(p)의 높이는 같은 그리드 라인에 걸린 모든 카드 중 가장 큰 값으로 통일되고, 3행(button[data-open-project])은 항상 그 아래 같은 위치에서 시작합니다.
4. 실행 및 확인
1. projects.html의 프로젝트 설명 텍스트 하나를 임시로 3~4줄까지 늘려
봅니다.
2. 브라우저에서 카드 그리드를 확인합니다 — 설명이 길어진 카드의 제목·
설명 영역만 세로로 늘어나고, 같은 행에 있는 다른 카드들의 버튼도
전부 같은 높이에서 시작해야 합니다.
3. 늘렸던 텍스트를 원래대로 되돌리고 다시 확인합니다.- 개발자 도구의 Grid 오버레이(레이아웃 탭)를 켜면 부모 트랙과 카드 트랙이 겹쳐 표시되어, 카드가 실제로 부모 트랙을 상속했는지 눈으로 확인할 수 있습니다.
직접 해보기
grid-template-rows: auto 1fr auto의 가운데 값을auto로 바꾸면 설명 영역이 내용 길이만큼만 차지하게 됩니다. 버튼 줄 정렬이 어떻게 달라지는지 관찰해 보세요.- 태그 칩 목록(
.project-card .tags)을 위한 행을 하나 더 추가해, 부모 그리드를auto auto 1fr auto4행으로 늘려 보세요.
풀이 보기
.project-grid {
grid-template-rows: auto auto 1fr auto;
}
.project-card {
grid-row: span 4;
}
.project-card h2 { grid-row: 1; }
.project-card .tags { grid-row: 2; }
.project-card p { grid-row: 3; }
.project-card button[data-open-project] { grid-row: 4; }행 개수를 바꾸면 grid-row: span N의 숫자와 자식들의 grid-row 번호를 함께 맞춰야 합니다.
자주 하는 실수
| 증상 | 원인 | 고치는 법 |
|---|---|---|
subgrid를 줬는데 트랙이 안 맞음 | grid-row: span N을 빠뜨려 카드가 몇 칸을 차지할지 정의 안 됨 | 서브그리드를 쓰는 요소에 grid-row(또는 grid-column) span을 함께 지정한다 |
| 자식 요소가 행에 안 들어감 | 자식에 grid-row 번호를 안 줘서 브라우저가 자동 배치함 | 제목·설명·버튼 각각에 명시적 grid-row 번호를 지정한다 |
| 컨테이너 쿼리로 열 수가 바뀌면 서브그리드가 깨짐 | 열 수 변경 규칙과 행 서브그리드 규칙이 서로 다른 값을 덮어씀 | @container 블록 안에서는 grid-template-columns만 바꾸고 grid-template-rows: subgrid는 그대로 유지한다 |
| 구형 Safari(16 미만)에서 레이아웃이 무너짐 | 서브그리드가 2023-09 이전 버전에는 없음 | 최신 Safari로 확인하거나 @supports (grid-template-rows: subgrid))로 폴백을 준비한다 |