카드 리스트를 만들다 보면 매번 걸리는 게 있다. 카드마다 제목 길이가 다르니까, 어떤 건 제목이 두 줄이고 어떤 건 한 줄이다. 그러면 그 아래 본문 시작 위치가 어긋나고, 맨 아래 버튼 높이도 제각각이 된다. 카드 하나하나는 멀쩡한데 나란히 놓으면 지저분해 보인다.
지금까지는 이걸 억지로 맞췄다. 제목에 min-height를 박아서 두 줄 높이만큼 강제로 확보하거나, JS로 제일 긴 제목 높이를 재서 나머지에 적용하거나. 둘 다 유지보수가 별로다. 폰트 바뀌면 min-height 다시 계산해야 하고, JS는 리사이즈마다 다시 재야 한다.
진짜 문제는 카드가 독립된 그리드라는 것
카드 안을 display: grid로 짜면 제목·본문·버튼이 각자 행을 갖는다. 근데 이 그리드는 카드 하나 안에서만 유효하다. 옆 카드의 제목 행과 내 카드의 제목 행은 아무 관계가 없으니까, 서로 높이를 맞출 방법이 없는 거다.
Subgrid는 이걸 해결한다. 바깥 리스트 그리드가 정한 행 높이를, 카드가 그대로 물려받게 만든다. 그러면 모든 카드의 제목 행이 같은 높이, 본문 행이 같은 높이가 된다.
코드
.card-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 1rem;
}
.card {
display: grid;
/* 부모 그리드의 행 3개를 그대로 물려받는다 */
grid-template-rows: subgrid;
grid-row: span 3;
gap: 0.5rem;
}
핵심은 두 줄이다. grid-template-rows: subgrid로 부모의 행 트랙을 상속받고, grid-row: span 3으로 이 카드가 부모 그리드에서 세 행을 차지한다고 선언한다. 카드 안 요소들(제목, 본문, 버튼)은 이 세 행에 하나씩 들어간다.
이제 부모 그리드가 각 행 높이를 카드 전체에서 제일 큰 콘텐츠 기준으로 잡아준다. 3번 카드 제목이 두 줄이면, 1·2번 카드 제목 행도 같이 두 줄 높이가 된다. 자연히 본문 시작점과 버튼 위치가 카드끼리 딱 맞는다.
정리
min-height나 JS 계산 없이, CSS 두 줄로 카드 정렬이 끝난다. Subgrid는 이제 크롬·사파리·파이어폭스 모두 지원(Baseline 2023)이라 프로덕션에 바로 써도 된다.
포인트는 딱 하나다. 정렬을 맞추고 싶은 요소들의 부모가, 바깥 그리드의 행(또는 열)을 상속받게 만들어라. 카드뿐 아니라 폼 라벨·입력칸 정렬, 테이블처럼 생긴 리스트에도 똑같이 통한다.