📦 CSS Grid
1. display: grid의 중요성
웹 레이아웃을 만들 때, 과거에는 float이나 flexbox를 주로 사용했지만 복잡한 2차원 레이아웃을 만들 때는 한계가 있었습니다.
display: flex는 1차원(행 또는 열) 레이아웃에 최적화되어 있지만, CSS Grid는 행과 열을 동시에 다룰 수 있는 2차원 레이아웃 시스템입니다.
전체 웹페이지의 틀을 잡거나 복잡한 형태의 레이아웃을 만들 때 매우 유용합니다.
저와 같이 개발을 처음 시작하시는 분들은 display:flexbox는 비교적 쉽게 이해가 되지만 grid는 저는 조금 난해한 부분이 많아 이해를 하는데 힘들었습니다. (지금도 마찬가지입니다…ㅎㅎ)
그래서 오늘의 주제로 가져오게 되었습니다.
2. Flexbox와 Grid 비교
✅ Grid의 장점
-
2차원 레이아웃에 최적회: 행과 열을 동시에 제어하면서 복잡한 구조를 쉽게 만들 수 있습니다.
-
유지보수 용이성:
grid-template-aras를 사용하면 코드만 보고도 레이아웃 구조를 한눈에 파악할 수 있습니다. -
반응형 설계의 편리성:
repeat(auto-fit, minmax(...))와 같은 함수를 활용하면 미디어 쿼리 없이도 반응형 레이아웃을 만들 수 있습니다.
❌ Grid의 단점
-
1차원 정렬에는 과할 수 있음: 단순한 수평/수직 정렬에는 Flexbox가 더 간단하고 직관적입니다.
-
구형 브라우저 지원 문제: IE 등 구형 브라우저에서는 지원이 제한적일 수 있습니다.
3. Grid 기본 개념
-
Grid Container: display: grid 속성이 적용된 부모 요소를 말합니다. 이 컨테이너 안에 자식 요소들이 격자 모양으로 배치됩니다.
-
Grid Item: Grid Container의 직접적인 자식 요소를 뜻합니다. 이 아이템들이 격자 칸에 들어가는 실제 내용물이 됩니다.
-
Grid Line:: 격자를 나누는 수평, 수직 선을 의미해요. grid-column이나 grid-row 속성으로 아이템의 위치를 지정할 때 이 선의 번호를 사용합니다.
-
Grid Track: 두 개의 Grid Line 사이의 공간, 즉 행 또는 열을 말합니다.
-
Grid Cell: Grid의 가장 작은 단위로, 네 개의 Grid Line으로 둘러싸인 한 칸을 의미합니다.
-
Grid Area: 하나 이상의 Grid Cell이 합쳐져 만들어진 직사각형 영역입니다. 이름을 지정해서 특정 영역을 쉽게 만들 수 있어요.
4. Grid의 주요 속성
🔹 display: grid; – Grid 컨테이너 만들기
.container {
display: grid;
}
.container는 Grid 컨테이너가 되고, 그 안에 있는 모든 자식 요소들은 Grid 아이템이 됩니다.
🔹 grid-template-columns / grid-template-rows - 행과 열 설정
.container {
grid-template-columns: 100px 1fr 200px;
grid-template-rows: 50px 1fr;
}
-
fr: 남은 공간을 비율로 나누어 가집니다. (fraction의 약자) -
repeat():repeat(3, 1fr)처럼 반복되는 열/행을 간결하게 정의할 수 있습니다.
🔹 grid-template-areas - 레이아웃 영역 이름 지정
.container {
grid-template-areas:
"header header"
"sidebar main";
}
- 각 영역에 이름을 부여해 레이아웃의 구조를 한눈에 파악할 수 있게 해줍니다.
🔹 gap - 아이템 간 간격 설정
.container {
gap: 20px; /* 행과 열 모두 20px 간격 */
/* 또는 */
gap: 20px 30px; /* 행 간격 20px, 열 간격 30px */
}
🔹 grid-column / grid-row - 아이템의 위치 및 크기 설정
.item {
grid-column: 1 / 3; /* 1번 라인부터 3번 라인까지 차지 */
grid-row: 2 / span 2; /* 2번 라인부터 2칸 차지 */
}
4. 자주 헷갈리는 부분 정리
🔍 fr 단위의 의미
fr은 Grid 레이아웃에서 가장 중요한 단위 중 하나입니다. grid-template-columns: 200px 1fr 1fr은 컨테이너 너비에서 200px을 뺀 나머지 공간을 두 아이템이 1:1 비율로 나누어 가진다는 의미입니다.
🔄 grid-template-areas와 grid-area의 차이점
-
grid-template-areas: Grid 컨테이너에 적용하며, 전체 레이아웃의 영역들을 정의합니다. -
grid-area: Grid 아이템에 적용하며, 해당 아이템이 어떤 영역에 위치할지 이름을 지정하거나row-start/col-start/row-end/col-end형식으로 위치를 직접 설정합니다.
🧱 justify-content vs justify-items
-
justify-content: Grid 자체를 컨테이너 내에서 수평으로 정렬합니다. -
justify-items: 개별 Grid 아이템의 내용을 수평으로 정렬합니다. (Flexbox의 justify-content와는 다른 동작 방식)
5. Grid 심화
🔹 미디어 쿼리 없는 반응형 Grid
repeat(auto-fit, minmax(250px, 1fr))를 사용하면 화면 크기에 따라 자동으로 열의 개수를 조절하는 유연한 레이아웃을 만들 수 있습니다.
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}
🔹 Subgrid 활용하기
display: subgrid는 중첩된 그리드 아이템이 부모 그리드의 열이나 행을 그대로 상속받게 해줍니다. 예를 들어, 카드 리스트에서 모든 카드의 제목, 내용, 버튼 위치를 완벽하게 맞출 때 유용합니다.
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.card {
display: grid;
grid-template-rows: subgrid; /* 부모의 행을 상속 */
grid-row: span 3; /* 세 칸 차지 */
}
🔹 grid-auto-rows와 grid-auto-flow
-
grid-auto-rows: 명시적으로 정의되지 않은 행의 크기를 자동으로 설정합니다. -
grid-auto-flow: 아이템이 자동으로 배치되는 방향을 제어합니다.
6. 예제: Grid를 활용한 레이아웃 구성
기본 예제
1. 기본 웹사이트 레이아웃
.layout {
display: grid;
min-height: 100vh;
grid-template-columns: 250px 1fr;
grid-template-rows: 80px 1fr 60px;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
2. 카드 그리드 레이아웃
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
padding: 20px;
}
.card {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
3. 성배 레이아웃 (Holy Grail Layout)
.holy-grail {
display: grid;
grid-template-columns: 200px 1fr 150px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main ads"
"footer footer footer";
min-height: 100vh;
}
4. 매거진 스타일 레이아웃
.magazine {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: repeat(4, 200px);
gap: 10px;
}
.featured {
grid-column: 1 / 4;
grid-row: 1 / 3;
}
.story-1 {
grid-column: 4 / 7;
grid-row: 1;
}
.story-2 {
grid-column: 4 / 6;
grid-row: 2;
}
반응형 Grid 설계
1. 미디어 쿼리 없는 반응형
/* 자동으로 반응하는 그리드 */
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}
2. 복잡한 반응형 레이아웃
.responsive-layout {
display: grid;
gap: 20px;
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
}
@media (min-width: 768px) {
.responsive-layout {
grid-template-columns: 1fr 300px;
grid-template-areas:
"header header"
"main sidebar"
"footer footer";
}
}
@media (min-width: 1024px) {
.responsive-layout {
grid-template-columns: 250px 1fr 300px;
grid-template-areas:
"nav header header"
"nav main sidebar"
"nav footer footer";
}
}
3. Container Queries와 Grid
.card-container {
container-type: inline-size;
}
.card-grid {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
}
@container (min-width: 400px) {
.card-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@container (min-width: 600px) {
.card-grid {
grid-template-columns: repeat(3, 1fr);
}
}
심화 예제
1. Subgrid 활용하기
.main-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.sub-container {
display: grid;
grid-template-columns: subgrid;
grid-column: 1 / 4;
gap: inherit;
}
2. 암시적 그리드 제어
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* 암시적으로 생성되는 행의 크기 */
grid-auto-rows: minmax(100px, auto);
/* 아이템이 배치되는 방향 */
grid-auto-flow: row | column | row dense | column dense;
}
3. 동적 그리드 아이템
.dynamic-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-auto-rows: 200px;
gap: 10px;
}
.item:nth-child(3n) {
grid-row: span 2;
}
.item:nth-child(5n) {
grid-column: span 2;
}
4. 오버랩 레이아웃
.overlap-container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 200px);
}
.background-image {
grid-column: 1 / 5;
grid-row: 1 / 4;
z-index: 1;
}
.content-overlay {
grid-column: 2 / 4;
grid-row: 2 / 3;
z-index: 2;
background: rgba(255, 255, 255, 0.9);
padding: 20px;
}
7. 코딩하면서 자주 하는 실수들
1. fr 단위 오해
/* 잘못된 사용 */
.wrong {
grid-template-columns: 200px 1fr 1fr; /* 200px + 남은공간의 1/2 + 남은공간의 1/2 */
}
/* 올바른 사용 */
.correct {
grid-template-columns: 200px 2fr 1fr; /* 고정폭 + 남은공간의 2/3 + 남은공간의 1/3 */
}
2. grid-area 순서 혼동
/* 올바른 순서: row-start / column-start / row-end / column-end */
.item {
grid-area: 1 / 2 / 3 / 4;
}
3. 불필요한 복잡성
/* 복잡한 방법 */
.complex {
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 2;
grid-row-end: 4;
}
/* 간단한 방법 */
.simple {
grid-area: 2 / 1 / 4 / 3;
}
8. 추가 학습 자료
-
A Complete Guide to Grid
(시각적 이해를 돕는 예제가 많습니다.) -
Grid Garden 게임
(간단한 게임을 통해 Grid를 학습할 수 있습니다.)
8. Oneul Code를 정리하며…
오늘 Grid에 대해서 학습하고 블로그 게시물을 작성하면서 직접 코드를 작성하고 글을 써보니, Flexbox와 Grid가 어떤 점에서 다른지,
그리고 복잡한 레이아웃을 grid속성을 활용해 만들 수 있는지 이해하게 되었습니다.
Oneul Code는 오늘 학습한 내용을 기록하면서,
이 글을 읽는 여러분도 바로 활용할 수 있기를 바랍니다.