한 줄 요약 —
display: grid는 요소 안을 모눈종이처럼 가로·세로 칸으로 나눈다. 세로 칸(열)의 개수와 폭은grid-template-columns로, 가로 칸(행)은grid-template-rows로 정하고, 칸 사이 간격은gap으로 준다. 폭을 비율대로 나누는fr단위까지 익혀 3×3 사진 갤러리를 만든다.
학습 목표#
display: grid가 Flexbox의 한 줄 정렬과 무엇이 다른지 설명할 수 있다.grid-template-columns로 열의 개수와 폭을,grid-template-rows로 행의 높이를 정할 수 있다.fr단위가 무엇이고px와 어떻게 다른지 안다.gap과repeat()를 써서 3×3 격자를 만들 수 있다.
오늘의 비유 — 모눈종이 위에 박스를 그리듯 위치를 정한다#
지난 회차의 Flexbox는 한 줄(또는 한 열)에 선 사람들을 정렬하는 도구였다. Grid는 출발점이 다르다. 책상에 모눈종이 한 장을 펼쳤다고 해 보자. 먼저 연필로 세로줄을 그어 폭이 정해진 칸을 만들고, 가로줄을 그어 높이가 정해진 칸을 만든다. 그러면 종이 전체가 바둑판 같은 칸으로 나뉜다.
이제 사진을 한 장씩 칸에 붙이기만 하면 된다. 칸의 크기와 자리는 종이가 이미 정해 뒀으니 사진이 알아서 제자리를 잡는다. Grid의 핵심이 여기 있다 — 내용을 먼저 늘어놓는 게 아니라, 칸(격자)을 먼저 그리고 그 위에 내용을 올린다. 가로와 세로를 동시에 다룰 수 있는 것도 평평한 모눈종이라서 가능하다.
핵심 개념#
display: grid — 칸을 그릴 종이를 펼친다#
컨테이너에 display: grid를 주면 그 안의 직계 자식들이 격자 위 칸에 하나씩 놓인다. 아직 줄을 안 그었다면 기본값은 세로로 한 칸씩 쌓이는 한 열짜리다.
.gallery {
display: grid;
}
grid-template-columns — 세로줄을 긋는다#
css grid를 시작할 때 가장 먼저 만나는 속성이다. 적어 준 값의 개수만큼 열이 생기고, 각 값이 그 열의 폭이 된다.
.gallery {
display: grid;
grid-template-columns: 100px 100px 100px; /* 100px짜리 열 3개 */
}
자식이 4개면 4번째는 자동으로 다음 가로줄(행)로 넘어간다. 행은 따로 안 그어도 내용 수에 맞춰 알아서 생긴다.
fr 단위 — 남은 공간을 비율로 나눈다#
폭을 px로 박으면 화면이 넓어져도 칸은 그대로다. fr는 fraction(비율)의 약자로, 남은 공간을 몇 등분할지를 뜻한다.
.gallery {
grid-template-columns: 1fr 1fr 1fr; /* 폭을 똑같이 3등분 */
}
같은 값이 반복되면 repeat()로 줄여 쓴다. 폭이 똑같은 12칸 격자도 한 줄이면 된다.
.gallery {
grid-template-columns: repeat(3, 1fr); /* 위와 같은 뜻 */
}
grid-template-rows와 gap#
행의 높이를 정하고 싶으면 grid-template-rows로 가로줄을 긋는다. 칸 사이 간격은 gap 한 줄로 준다(margin이 아니다).
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 120px 120px;
gap: 12px; /* 칸 사이 간격 */
}
함께 따라하기 — 3×3 사진 갤러리#
모눈종이에 세로 3칸을 긋고 사진 9장을 차례로 붙여 본다.
<div class="gallery">
<img src="/photo-1.jpg" alt="갤러리 사진 1" />
<img src="/photo-2.jpg" alt="갤러리 사진 2" />
<img src="/photo-3.jpg" alt="갤러리 사진 3" />
<!-- 같은 식으로 9장까지 -->
</div>
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
.gallery img {
width: 100%;
aspect-ratio: 1 / 1; /* 정사각 칸 */
object-fit: cover; /* 칸에 꽉 차게 자른다 */
}
저장하고 열어 보면 사진 9장이 가로 3장씩 세 줄, 즉 3×3 격자로 가지런히 놓인다. 브라우저 폭을 넓히면 1fr 칸들이 함께 넓어지고, gap 덕분에 사진 사이 흰 틈은 일정하게 유지된다. 행은 따로 안 그었지만 사진이 9장이라 알아서 세 줄이 만들어진다.
흔한 실수 3가지#
1. fr 단위를 px처럼 생각한다#
fr를 고정 크기로 오해하면 칸 폭이 예상과 달라 헤맨다. 1fr는 "1px"이 아니라 "남은 공간 1몫"이다.
/* (세 칸이 1:1:2 비율로 나뉩니다 — 100px씩이 아닙니다) */
.grid {
grid-template-columns: 1fr 1fr 2fr;
}
fr는 먼저 px·%로 정해진 칸을 뺀 남은 공간을 비율대로 나눈다. 그래서 200px 1fr 1fr이라면 200px을 떼고 남은 폭을 두 1fr가 반씩 가진다. 칸 폭을 정확히 못 박고 싶을 때만 px를 쓰고, 화면에 맞춰 늘어나야 하면 fr를 쓴다.
2. 행 기반으로 짜야 할 때 열만 건드린다#
세로로 쌓인 칸(행)의 높이를 바꾸고 싶은데 grid-template-columns만 계속 만지는 경우다.
/* (행 높이를 바꾸려는데 열 설정만 건드리고 있습니다) */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
열은 grid-template-columns, 행은 grid-template-rows가 맡는다. 모눈종이의 세로줄과 가로줄을 따로 긋는 것과 같다. 행 높이를 정하려면 가로줄을 그어야 한다.
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 200px 120px; /* 가로줄(행)의 높이 */
}
3. flex로 충분한 레이아웃에 grid를 과하게 쓴다#
로고·메뉴·버튼을 한 줄에 놓는 것처럼 한 방향만 정렬하는 일은 지난 회차의 Flexbox가 더 간단하다. 모눈종이를 펼칠 것 없이 한 줄에 세우면 되는 일이다.
/* 한 줄 정렬에 굳이 격자를 그릴 필요는 없습니다 */
.header { display: flex; gap: 16px; align-items: center; }
가로·세로를 동시에 나눠야 할 때(사진 갤러리, 카드 격자, 대시보드) Grid가 빛난다. "한 줄이면 flex, 격자면 grid"가 무난한 기준이다.
오늘 배운 것 체크리스트#
-
display: grid는 가로·세로를 동시에 칸으로 나눈다(flex는 한 방향). - 열은
grid-template-columns, 행은grid-template-rows로 정한다. -
fr는 고정 크기가 아니라 남은 공간의 몫이다. - 같은 값이 반복되면
repeat(3, 1fr)로 줄여 쓴다. - 칸 사이 간격은
margin이 아니라gap으로 준다.
자주 묻는 질문#
Q. 1fr이 정확히 무슨 뜻인가요?
A. fr는 fraction(비율)의 약자로, 먼저 정해진 고정 폭을 뺀 남은 공간을 몇 등분할지를 나타냅니다. 1fr 1fr은 남은 폭을 반씩, 1fr 2fr은 1:2로 나눕니다. px처럼 고정 크기가 아니라 화면 폭에 따라 늘었다 줄었다 합니다.
Q. Flexbox로도 격자 레이아웃을 만들 수 있는데 Grid를 왜 쓰나요?
A. Flexbox는 기본적으로 한 줄(또는 한 열) 정렬에 강합니다. 줄바꿈을 해도 위아래 행과 좌우 열을 동시에 맞추기는 번거롭습니다. Grid는 가로·세로 칸을 먼저 정의하므로, 사진 갤러리나 카드 격자처럼 두 방향을 함께 맞춰야 하는 css 격자 레이아웃에서 코드가 훨씬 단순합니다.
Q. 12칸짜리 격자는 어떻게 만드나요?
A. grid-template-columns: repeat(12, 1fr) 한 줄이면 폭이 똑같은 12개 열이 생깁니다. 많은 디자인 시스템이 12칸을 기준으로 삼는 건 2·3·4·6으로 깔끔하게 나눠지기 때문입니다. 이 칸들을 묶어 영역을 만드는 법은 다음 회차에서 다룹니다.
다음 시간 예고#
내일은 Grid 심화 — grid-area와 auto-fit/auto-fill을 다룬다. 오늘 그린 칸들을 이름으로 묶어 배치하고, 화면 폭에 따라 카드가 알아서 줄바꿈되는 격자를 만들어 본다.