안녕하세요! 프론트엔드 개발 강사입니다. 이번에 가져오신 내용은 CSS Grid의 꽃이자, 레이아웃을 마치 그림 그리듯이 직관적으로 짤 수 있게 해주는 그리드 템플릿 영역(Grid template areas)에 대한 문서군요!
이전 가이드에서 배웠던 '선(line) 번호'를 세어가며 배치하는 방식도 좋지만, 복잡한 레이아웃을 짤 때는 숫자가 헷갈리기 쉽습니다. 하지만 오늘 배울 이 방식을 사용하면, CSS 코드만 봐도 화면이 어떻게 구성되어 있는지 한눈에 알 수 있습니다. 오죽하면 이 방식을 "아스키 아트(ASCII-art) 레이아웃"이라고 부를 정도니까요! 제가 실무에서 이 기능을 어떻게 활용하는지, 꿀팁과 함께 알기 쉽게 번역해 드리겠습니다. 😊
선(line) 기반 배치를 사용한 그리드 레이아웃 가이드에서는 그리드 선이 무엇인지, 그리고 아이템들을 그 선에 맞춰 어떻게 배치하는지 살펴보았습니다. CSS 그리드 레이아웃을 사용할 때 여러분은 항상 이 '선(lines)'을 가지게 되며, 이는 아이템을 배치하는 아주 직접적이고 간단한 방법입니다.
하지만, 그리드에 아이템을 배치하는 또 다른 대안적인 방법이 있습니다. 이 방법은 단독으로 쓰일 수도 있고, 앞서 배운 선 기반 배치와 섞어서 쓰일 수도 있죠. 이 방법은 바로 이름이 지어진 템플릿 영역(named template areas)을 사용해서 아이템을 배치하는 것입니다. 조금만 읽어보시면 왜 사람들이 이 방법을 가리켜 그리드 레이아웃의 '아스키 아트(ASCII-art)' 기법이라고 부르는지 금방 깨닫게 되실 겁니다!
grid-template-areas 사용하기 (Using grid-template-areas for UI elements)여러분은 이미 grid-area라는 속성을 본 적이 있으실 겁니다. 이 속성은 그리드 영역의 위치를 잡기 위해 4개의 선 번호(row-start / column-start / row-end / column-end)를 한 번에 값으로 받을 수 있는 단축 속성입니다.
.box1 {
grid-area: 1 / 1 / 4 / 2; /* 1행 1열부터 시작해서, 4행 2열 앞에서 끝나라! */
}
위의 코드처럼 4개의 선 번호를 모두 적어준다는 것은, 결국 그 선들이 둘러싸고 있는 하나의 '영역(area)'을 정의하는 것과 같습니다.

하지만 선 번호 대신, 이 영역에 직접 '이름'을 지어주고, 그 이름이 들어갈 위치를 부모 컨테이너의 grid-template-areas 속성에 적어 넣는 방식으로도 영역을 정의할 수 있습니다!
영역의 이름은 여러분이 원하는 대로 자유롭게 지을 수 있습니다. 예를 들어, 아래 이미지와 같은 레이아웃을 만들고 싶다면, 크게 4개의 주요 영역으로 나눌 수 있습니다:

이제 grid-area 속성을 사용해서 이 각각의 요소들에게 이름을 붙여주겠습니다. 주의할 점은, 이름을 붙이는 것 자체만으로는 화면에 어떤 레이아웃도 그려지지 않는다는 것입니다. 그저 나중에 레이아웃 판에서 사용할 수 있는 '이름표(명찰)'를 달아준 것뿐이죠.
.header {
grid-area: hd; /* 내 이름은 앞으로 hd다! */
}
.footer {
grid-area: ft; /* 내 이름은 ft야! */
}
.content {
grid-area: main; /* 나는 main! */
}
.sidebar {
grid-area: sd; /* 나는 sd! */
}
이렇게 아이템들에게 이름표를 달아준 다음, 본격적으로 레이아웃의 판을 짭니다. 이번에는 아이템 자신에게 선 번호를 매겨서 일일이 위치를 잡아주는 대신, 부모(그리드 컨테이너)에서 전체 레이아웃의 큰 그림을 그립니다.
아래 예제에서는 9열(column)짜리 그리드를 만듭니다. 그리고 hd(헤더)와 ft(푸터) 영역은 가로로 9칸을 전부 차지하게(span) 만들고, sd(사이드바)는 3칸, main(콘텐츠)은 6칸을 차지하게 만들 겁니다. 각 영역의 세로 높이는 1줄(row)씩만 사용합니다.
(MDN Playground에서 실행해보기 (Play))
.wrapper {
display: grid;
grid-template-columns: repeat(9, 1fr); /* 똑같은 크기의 9칸짜리 기둥(열) 생성! */
grid-auto-rows: minmax(100px, auto); /* 최소 높이는 100px */
grid-template-areas:
"hd hd hd hd hd hd hd hd hd"
"sd sd sd main main main main main main"
"ft ft ft ft ft ft ft ft ft";
}
<div class="wrapper">
<div class="header">Header</div>
<div class="sidebar">Sidebar</div>
<div class="content">Content</div>
<div class="footer">Footer</div>
</div>
👨🏫 강사의 실무 팁! "아스키 아트 레이아웃의 마법"
grid-template-areas코드를 가만히 들여다보세요. 위에서부터 아래로, 첫째 줄엔hd(헤더)가 9칸을 다 채우고 있고, 둘째 줄엔sd(사이드바)가 3칸,main이 6칸, 마지막 줄엔ft(푸터)가 9칸을 채우고 있죠?
코드가 곧 화면의 미니맵입니다! 이 직관성이 바로grid-template-areas를 실무에서 사랑할 수밖에 없는 이유랍니다.
이 방법을 사용하면 개별 그리드 아이템(자식) 쪽에는 복잡한 위치 지정 코드를 단 한 줄도 적을 필요가 없습니다. 모든 레이아웃의 통제권이 부모인 그리드 컨테이너에 집중되죠. 우리는 그저 grid-template-areas 속성에 그려진 문자열 배열만 보고도 전체 레이아웃 구조를 완벽하게 파악할 수 있습니다.
방금 전 예제에서는 그리드의 모든 칸을 이름들로 꽉꽉 채워서 남는 흰 여백이 하나도 없게 만들었습니다. 하지만 이 레이아웃 방식에서도 얼마든지 특정 그리드 칸을 텅 비워둘 수 있습니다.
특정 칸을 비워두려면 마침표(점) 기호인 . 을 사용하면 됩니다. 만약 메인 콘텐츠(main) 바로 아래쪽에만 푸터를 두고, 사이드바 아래쪽 3칸은 텅 비워두고 싶다면 어떻게 해야 할까요?
(MDN Playground에서 실행해보기 (Play))
.wrapper {
display: grid;
grid-template-columns: repeat(9, 1fr);
grid-auto-rows: minmax(100px, auto);
grid-template-areas:
"hd hd hd hd hd hd hd hd hd"
"sd sd sd main main main main main main"
". . . ft ft ft ft ft ft"; /* 점(.)을 찍은 곳은 텅 빈 공간이 됩니다! */
}
<div class="wrapper">
<div class="header">Header</div>
<div class="sidebar">Sidebar</div>
<div class="content">Content</div>
<div class="footer">Footer</div>
</div>
💡 코드 정리 팁:
레이아웃 문자열을 적을 때 여러 개의.을 겹쳐서...이라고 적어도, 중간에 띄어쓰기(white space)가 없다면 전부 합쳐서 단 '한 칸'을 비운 것으로 간주됩니다. 복잡한 레이아웃을 짤 때는 코드를 시각적으로 반듯하게 줄 맞추기 위해 점과 공백을 넉넉히 섞어 쓰는 것이 좋습니다. 이렇게 하면 CSS 코드 자체만 봐도 실제 화면이 어떻게 생겼는지 한눈에 렌더링 된 모습을 상상할 수 있거든요!
우리의 예제에서 각 영역은 여러 개의 그리드 셀(칸)을 가로지르며 병합(span)되어 있습니다. 우리는 그저 띄어쓰기로 구분하여 같은 이름을 여러 번 반복해서 적어줌으로써 셀 병합을 이루어냈죠.
grid-template-areas의 문자열 안에서 각 칸들이 예쁘게 줄을 맞출 수 있도록 여러분 마음대로 공백(스페이스바)을 넉넉히 추가하셔도 좋습니다. 예제 코드에서도 hd와 ft 영역이 main 영역과 시각적으로 줄을 맞추기 위해 중간에 공백을 여러 개 둔 것을 볼 수 있습니다.
[주의사항] 이름을 반복해서 만들어낸 병합 영역은 반드시 직사각형(rectangular) 모양이어야만 합니다. "L"자 모양이나 "T"자 모양의 영역은 만들 수 없습니다. (사양서에는 미래 버전에 이런 비정형 모양을 지원할 수도 있다고 적혀있긴 합니다만, 아직은 불가능합니다.)
가로(열)를 병합했던 것만큼 세로(행)를 병합하는 것도 아주 쉽습니다. 예를 들어, 사이드바(sd)가 콘텐츠(main) 옆뿐만 아니라 그 아래쪽 푸터(ft)가 있는 줄까지 길게 아래로 뻗어 내려가게 하고 싶다면? 아까 비워두었던 세 번째 줄의 . 부분들을 다시 sd로 채워주기만 하면 됩니다.
(MDN Playground에서 실행해보기 (Play))
.wrapper {
display: grid;
grid-template-columns: repeat(9, 1fr);
grid-auto-rows: minmax(100px, auto);
grid-template-areas:
"hd hd hd hd hd hd hd hd hd"
"sd sd sd main main main main main main"
"sd sd sd ft ft ft ft ft ft"; /* sd가 위에서 아래로 2줄을 차지하게 되었습니다! */
}
grid-template-areas의 값은 반드시 완벽하게 채워진 그리드의 모습을 나타내야 합니다. 그렇지 않으면 문법 오류(invalid)로 간주되어 속성 자체가 아예 무시됩니다.
다시 말해, 모든 줄(row)은 정확히 똑같은 개수의 셀(단어 개수)을 가져야만 합니다. 칸을 비워둘 거라면 반드시 . 문자를 사용해서 빈칸이라는 걸 명시해야 합니다. 또한, 같은 이름으로 묶인 구역이 직사각형이 아닐 경우(예: 한 줄만 삐져나온 형태)에도 역시 잘못된 그리드 코드로 처리되어 화면이 망가진다는 점을 명심하세요.
이 방식의 가장 큰 장점은 레이아웃의 구조가 CSS의 딱 '한 곳(부모 컨테이너)'에 몰려있다는 것입니다. 덕분에 화면 크기가 바뀌는 브레이크포인트(breakpoints, 미디어 쿼리)마다 레이아웃을 완전히 뒤엎는 작업이 너무나도 쉬워집니다!
그리드의 뼈대(행/열 개수)를 바꾸거나, 아이템들이 위치하는 배치도를 바꾸거나, 아니면 둘 다 한꺼번에 싹 바꿀 수 있죠.
이 작업을 할 때, 각 아이템에 이름표(grid-area)를 붙여주는 코드는 미디어 쿼리 바깥(전역)에 한 번만 선언해 두세요. 그러면 화면이 넓든 좁든 간에 메인 콘텐츠는 항상 main이라는 이름을 가지게 되니까요.
예를 들어, 우리가 만든 위의 레이아웃을 모바일 같은 좁은 화면(narrow widths)에서는 아주 단순하게, 그냥 1열(single column)짜리 그리드로 만들어서 4개의 요소가 위에서 아래로 차곡차곡 쌓이게 만들고 싶다고 해보죠.
/* 기본 상태 (모바일 등 좁은 화면): 1열로 쭉 쌓습니다 */
.wrapper {
display: grid;
grid-auto-rows: minmax(100px, auto);
grid-template-columns: 1fr; /* 1칸짜리 레이아웃 */
grid-template-areas:
"hd"
"main"
"sd"
"ft";
}
이제 미디어 쿼리를 써서 화면이 조금 넓어지거나, 아주 넓어졌을 때 이 레이아웃 판을 다시 짜보겠습니다. 가장 넓은 화면에서는 애초에 계획했던 9열짜리 레이아웃 대신, 좌우 양쪽에 사이드바가 있는 것 같은 좀 더 색다른 배치를 만들어 보겠습니다. (물론 아이템의 이름표 설정 코드는 그대로 둔 채 말이죠!)
(MDN Playground에서 실행해보기 (Play))
/* 화면 너비가 30em(태블릿) 이상일 때 */
@media (width >= 30em) {
.wrapper {
grid-template-columns: repeat(9, 1fr);
grid-template-areas:
"hd hd hd hd hd hd hd hd hd"
"sd sd sd main main main main main main"
"sd sd sd ft ft ft ft ft ft";
}
}
/* 화면 너비가 60em(데스크탑) 이상일 때 */
@media (width >= 60em) {
.wrapper {
/* 9열 구조는 그대로 둔 채, 배치도만 싹 바꿔줍니다! */
grid-template-areas:
"hd hd hd hd hd hd hd hd hd"
"sd sd main main main main main ft ft"; /* 푸터가 오른쪽 옆구리로 올라왔네요! */
}
}
👨🏫 강사의 실무 팁! "반응형 레이아웃의 끝판왕"
예전에 Float이나 Position으로 반응형 웹을 짤 때는, 모바일 화면으로 갈 때마다 요소들의 너비(width), 마진, 플롯 해제 등을 일일이 초기화하느라 코드가 스파게티처럼 꼬이곤 했죠.
하지만grid-template-areas를 쓰면, 미디어 쿼리 안에서 그냥 "아스키아트 퍼즐의 모양만 새롭게 그려주면" 모든 요소들이 알아서 새로운 자기 자리를 찾아가서 찰싹 달라붙습니다! 정말 혁명적인 기능이죠.
grid-template-areas 사용하기 (Using grid-template-areas for UI elements)인터넷에서 Grid 튜토리얼을 찾아보면, 대부분 Grid를 웹사이트 '전체 페이지 레이아웃(전체 뼈대)'을 잡는 데 사용하는 거창한 예제들만 나옵니다. 하지만 Grid는 작은 컴포넌트(section) 단위의 레이아웃을 짤 때도 엄청나게 유용합니다! 특히 grid-template-areas를 사용하면, 코드를 보는 것만으로도 이 컴포넌트가 시각적으로 어떻게 생겼는지 직관적으로 알 수 있어서 유지보수에 큰 도움이 되죠.
한쪽에는 사진(미디어)이 있고 다른 한쪽에는 글(콘텐츠)이 나란히 놓여있는 아주 흔한 컴포넌트인 "미디어 오브젝트(media object)"를 이 기능으로 만들어 보겠습니다. 상황에 따라 사진이 글의 왼쪽에 있을 수도 있고, 오른쪽에 있을 수도 있는 구조입니다.

우선 2칸(column)짜리 그리드를 만듭니다. 이미지가 들어갈 칸은 1fr 비율로, 텍스트가 들어갈 칸은 3fr 비율로 너비를 줍니다. (만약 이미지 크기를 딱 고정하고 싶다면 이미지 칸에 픽셀(px) 단위로 너비를 주고, 텍스트 칸에만 1fr을 주어 남는 공간을 다 쓰게 만들 수도 있습니다.)
이미지 영역에는 img라는 이름을, 텍스트 영역에는 content라는 이름을 달아준 다음, grid-template-areas를 사용해 이 둘을 나란히 눕혀보겠습니다.
(MDN Playground에서 실행해보기 (Play))
.media {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas: "img content"; /* 이미지가 왼쪽, 텍스트가 오른쪽! */
}
.media .image {
grid-area: img;
}
.media .text {
grid-area: content;
}
<div class="media">
<div class="image"></div>
<div class="text">
이것은 미디어 오브젝트 예제입니다. grid-template-areas를 사용하면
이미지와 텍스트 파트의 위치를 아주 손쉽게 바꿀 수 있습니다.
</div>
</div>
만약 이미지가 오른쪽으로 가게 좌우를 확 뒤집고 싶다면 어떻게 할까요? HTML 태그 순서를 건드릴 필요가 없습니다. 부모 컨테이너의 그리드 트랙 설정(1fr 3fr)을 반대로 뒤집고(3fr 1fr), grid-template-areas 안의 단어 순서만 슥 바꿔주면 끝납니다!
(MDN Playground에서 실행해보기 (Play))
/* flipped 클래스가 붙으면 배치를 완전히 반대로 뒤집습니다 */
.media.flipped {
grid-template-columns: 3fr 1fr;
grid-template-areas: "content img"; /* 텍스트가 왼쪽, 이미지가 오른쪽! */
}
<div class="media flipped">
<div class="image"></div>
<div class="text">
이것은 미디어 오브젝트 예제입니다. grid-template-areas를 사용하면
이미지와 텍스트 파트의 위치를 아주 손쉽게 바꿀 수 있습니다.
</div>
</div>
지금까지 그리드에 아이템을 배치하는 여러 방법과 관련된 속성들을 살펴보았는데요, 이제 그리드의 뼈대와 배치 정보 등을 단 한 줄의 CSS로 모두 정의할 수 있게 해주는 아주 쿨한(하지만 복잡한) 단축 속성(shorthands) 두 가지를 소개해 드리겠습니다.
이 단축 속성들은 너무 많은 정보가 한 줄에 압축되다 보니, 다른 개발자들이나 (심지어 미래의 여러분 자신조차) 읽고 해석하기 꽤 까다로울 수 있습니다. 하지만 이 역시 공식 사양서의 일부이며, 다른 사람들이 짠 코드나 예제에서 이 문법을 마주칠 일이 분명히 있을 테니 어떤 식으로 작동하는지는 알아두는 것이 좋습니다. (물론 여러분 본인은 이 단축 속성 대신 길고 명확하게 풀어쓰는 걸 선호할 수도 있습니다.)
단축 속성을 쓸 때 반드시 명심해야 할 점이 있습니다. 단축 속성은 여러분이 적어 넣은 여러 값들을 한 번에 세팅해 주는 역할도 하지만, 여러분이 생략하고 적지 않은(또는 적을 수 없는) 나머지 모든 관련 속성들을 그들의 '초기 기본값(initial values)'으로 싹 다 초기화(reset) 시켜버린다는 무서운 성질을 가지고 있습니다.
따라서 다른 곳에서 열심히 속성을 세팅해 뒀는데, 이 단축 속성 한 줄 때문에 덮어씌워져서 날아갈 수도 있다는 점을 항상 경계해야 합니다.
그리드 컨테이너에 쓸 수 있는 두 가지 단축 속성에는 명시적 그리드 단축 속성인 grid-template과, 그리드 종합 정의 단축 속성인 grid가 있습니다.
grid-templategrid-template 단축 속성은 다음 세 가지 하위 속성(longhand properties)을 한 방에 설정해 줍니다:
이 속성이 명시적 그리드 단축 속성(explicit grid shorthand)이라고 불리는 이유는, 개발자가 "직접 그림을 그려가며 크기를 통제하는" 명시적 그리드(explicit grid)의 값들만 설정하기 때문입니다. 브라우저가 아이템 개수가 넘쳐서 스스로 몰래 만들어내는 '암시적(implicit) 행/열 트랙'에는 전혀 영향을 주지 않죠.
다음 코드는 우리가 이 가이드 초반에 만들었던 레이아웃을 grid-template 단축 속성 하나로 완벽하게 똑같이 만들어내는 모습입니다.
.wrapper {
display: grid;
grid-template:
"hd hd hd hd hd hd hd hd hd" minmax(100px, auto) /* 첫 번째 행의 배치 모양과, 그 행의 높이(rows) 지정 */
"sd sd sd main main main main main main" minmax(100px, auto) /* 두 번째 행의 배치 모양과, 그 행의 높이(rows) 지정 */
"ft ft ft ft ft ft ft ft ft" minmax(100px, auto) /* 세 번째 행의 배치 모양과, 그 행의 높이(rows) 지정 */
/ 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; /* 슬래시(/) 뒤에는 기둥(columns) 9개의 너비를 지정합니다 */
}
첫 번째 값들은 우리가 아는 grid-template-areas의 문자열(아스키아트) 값들입니다. 그런데 각 문자열(행) 끝에 이 줄의 높이(사이즈)가 얼마인지가 같이 선언되어 있죠? 여기서 minmax(100px, auto)가 바로 grid-template-rows 역할을 대신하고 있는 겁니다.
그리고 모든 행에 대한 정의가 끝나면 슬래시(/) 기호를 하나 적어줍니다. 그 뒤에 따라오는 것은 바로 기둥(column) 트랙들의 너비 목록, 즉 grid-template-columns의 역할입니다.
gridgrid 단축 속성은 방금 전의 grid-template보다 한 발 더 나아가서, 브라우저가 몰래 만들어내는 암시적 그리드(implicit grid) 관련 속성들까지 몽땅 초기화하고 설정해 버립니다. 즉, 다음 속성들을 모두 한 줄로 세팅(또는 리셋)하는 것이죠:
grid-template-rowsgrid-template-columnsgrid-template-areasgrid-auto-rows (암시적 행의 크기)grid-auto-columns (암시적 열의 크기)grid-auto-flow (자동 배치 방향)여러분은 이 grid 속성을 방금 배운 grid-template 단축 속성과 글자 하나 안 틀리고 똑같은 문법으로 사용할 수 있습니다. 단, 이 grid라는 녀석을 쓰면 위에 나열된 나머지 모든 auto-* 속성들이 싹 다 기본값으로 초기화되어 버린다는 무시무시한 사실만 꼭 명심하시면 됩니다.
.wrapper {
display: grid;
grid: /* grid-template과 작성 방식이 완벽히 똑같습니다! */
"hd hd hd hd hd hd hd hd hd" minmax(100px, auto)
"sd sd sd main main main main main main" minmax(100px, auto)
"ft ft ft ft ft ft ft ft ft" minmax(100px, auto)
/ 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
}
이 무시무시한 단축 속성(grid)이 제공하는 또 다른 기능들에 대해서는 나중에 그리드 레이아웃의 자동 배치(auto-placement in grid layout)와 grid-auto-flow 속성을 다룰 때 다시 한번 깊이 파보도록 하겠습니다.
지금까지 그리드 가이드 시리즈를 착실히 따라오셨다면, 이제 여러분은 선 기반 배치(line-based placement) 방식과 이름이 지어진 템플릿 영역(named template areas) 방식을 자유자재로 섞어가며 멋진 그리드 레이아웃을 짤 수 있는 실력자가 되셨을 겁니다!
이제 다음 가이드인 이름이 지어진 그리드 선을 활용한 레이아웃 만들기(grid layouts using named grid lines)로 넘어가서, 이 두 가지 방식을 섞어 쓰는 궁극의 팁을 배워보도록 합시다.
이 페이지가 도움이 되셨나요? [네 (Yes)] / [아니요 (No)]
기여하는 방법 알아보기 (Learn how to contribute)
이 페이지는 2025년 12월 15일에 MDN 기여자들 (MDN contributors)에 의해 마지막으로 수정되었습니다.