Grid Item은 늘어났는데 자식은 왜 안 늘어날까. align-items: stretch의 동작 원리, Indefinite Height 문제, 그리고 중첩 Grid 해결책까지.
CSS Grid는 웹 레이아웃의 역사를 바꾼 도구입니다. 하지만 막상 쓰다 보면 당황스러운 순간이 있습니다.
“Grid Item은 분명히 늘어났는데, 그 안의 자식은 왜 높이를 못 채울까?
이 질문에 답하려면 Grid Track 크기 결정과 아이템 정렬이라는 두 메커니즘을 함께 이해해야 합니다.
CSS Grid가 왜 필요했는지 이해하려면 이전까지의 레이아웃 방식을 봐야 합니다.
| 방식 | 문제 |
|---|---|
| Table Layout | 데이터 표시용 <table> 태그를 레이아웃에 억지로 사용. 시맨틱에 어긋남 |
| Float & Positioning | 이미지 주변 텍스트 흐름 제어용이던 float를 레이아웃에 전용. clearfix 같은 편법이 난무 |
| Flexbox | 1차원(행 또는 열) 레이아웃엔 훌륭하지만, 2차원 격자 레이아웃을 표현하기엔 한계 |
CSS Grid는 2011년 Microsoft의 제안에서 시작되었습니다. IE10에 처음 실험적으로 도입되었고, 이후 W3C 표준으로 채택되어 2017년 현대 브라우저 대부분에 탑재됩니다.
디자인 소프트웨어의 '그리드 시스템'을 브라우저 엔진에 직접 구현하려는 시도였습니다.
Grid의 행 높이는 그 행에 속한 아이템 중 가장 높은 요소의 콘텐츠를 기준으로 결정됩니다. CSS 용어로 max-content sizing이라고 합니다.
행 높이 결정 순서
1. 브라우저가 한 행의 모든 아이템 높이를 계산
2. 가장 높은 아이템 기준으로 "Grid Row Track" 높이 확정
3. 나머지 짧은 아이템들은 확정된 트랙 높이 안에 배치
┌──────────┬──────────┬──────────┐ ← Row Track 높이 = 아이템 C 기준
│ Item A │ Item B │ Item C │
│ │ │ (가장 │
│ │ │ 높음) │
└──────────┴──────────┴──────────┘
align-items: stretch는 Grid Container의 기본값입니다. 이 속성이 어떻게 작동하는지 이해하려면 Grid Area와 Grid Item의 차이를 알아야 합니다.
동작 단계
stretch가 적용된 경우, 아이템의 Border-box를 계산된 행 높이에 맞춥니다.height가 설정되어 있다면 stretch는 무시됩니다..container {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* align-items: stretch; ← 기본값, 생략해도 동일 */
}
stretch 적용 후
┌──────────┬──────────┬──────────┐
│ Item A │ Item B │ Item C │
│ (늘어남)│ (늘어남)│ (원래) │
│ │ │ │
└──────────┴──────────┴──────────┘
align-items: stretch가 설정되어 있다면 브라우저가 이미 아이템 높이를 트랙에 맞게 강제로 늘립니다.
Grid Item에 height: 100%를 따로 줄 필요가 없습니다.
많은 개발자가 겪는 문제입니다. Grid Item(자식)은 stretch로 늘어났는데, 그 내부의 <div>(손자)는 콘텐츠 크기만큼만 자리잡습니다.
원인: stretch는 명시적 높이가 아니다
CSS 명세상, stretch로 늘어난 높이는 계산된(computed) 높이이지 명시적(explicit) 높이가 아닙니다. 자식 요소가 height: 100%를 사용할 때, 부모의 높이가 명시적으로 확정되지 않으면 상속이 제대로 일어나지 않습니다.
Grid Item (stretch로 늘어남 — 시각적으로는 꽉 참)
└── 손자 <div> (height: 100% → 부모 높이가 "확정"이 아니므로 무시)
→ 콘텐츠 크기만큼만 렌더링됨
height: 100%를 손자에게 주면 될 것 같지만, 단정 짓기엔 위험합니다.
문제 상황
CSS에서 % 단위는 부모의 높이가 명시적으로 정해져 있을 때만 제대로 작동합니다.
auto이고 내부 콘텐츠에 의해 결정될 때, Grid Item은 stretch로 시각적으로 늘어납니다.height: 100%를 주면 부모 높이를 0 또는 콘텐츠 최소 높이로 인식해 정렬이 깨질 수 있습니다.CSS 명세에서 높이가 확정되지 않은 상태를 Indefinite Height라고 합니다.
Grid Container에 명시적 높이(px, vh 등)가 없으면 내부 아이템의 height: 100%는 예측 불가능하게 동작합니다.
/* 동작이 불안정한 패턴 */
.container {
display: grid;
/* height 없음 → Indefinite Height */
}
.item > .child {
height: 100%; /* 브라우저에 따라 0이 될 수 있음 */
}
height: 100%라는 수치에 의존하기보다, 레이아웃 컨텍스트를 하위로 전파하는 것이 현대적인 방식입니다.
Grid Item에도 display: grid를 부여하면 손자가 새로운 Grid 컨텍스트 안에서 안정적으로 배치됩니다.
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.item {
display: grid; /* Grid Item이 동시에 Grid Container */
grid-template-rows: 1fr; /* 손자가 전체 높이를 채움 */
}
.grandchild {
/* height: 100% 불필요 — Grid가 대신 처리 */
}
Grid 컨텍스트는 명시적 높이 없이도 확정적 높이를 하위로 전파합니다.
height: 100% 불필요 — stretch가 이미 처리height: 100%는 Indefinite Height 상황에서 깨질 수 있음% 계산에 의존하지 않음px, vh)가 있다면 height: 100%도 안정적으로 동작역사적으로 웹 레이아웃은 % 계산의 모호함을 해결하는 방향으로 발전해 왔습니다. height: 100%에 의존하는 대신 레이아웃 컨텍스트를 아래로 전파하는 것이 현대 CSS의 표준적인 접근입니다.