Skip to content
This page has been auto-translated and may contain errors.View in English

Grid

docs.scrimba.com

상단에는 헤더, 왼쪽에는 사이드바, 그리고 메인 콘텐츠 영역과 푸터가 있는 페이지가 있다고 해봅시다. 컨테이너를 겹겹이 중첩해서 하나씩 자리를 맞춰 넣을 수도 있고, 배치를 바꿔야 하는 날이 오기 전까지는 대체로 잘 동작할 것입니다. CSS 그리드는 바로 이런 형태의 문제, 즉 페이지를 행과 열 양쪽 방향으로 동시에 배치하는 문제를 위해 만들어졌습니다. 레이아웃을 트랙의 집합으로 표현할 수 있게 되면, 래퍼와 float를 이리저리 조정하던 작업 대부분이 사라집니다.

그리드 컨테이너

어떤 요소에든 display: grid를 지정하면 그 요소를 그리드로 바꿀 수 있습니다. 그 요소는 **그리드 컨테이너**가 되고, 그 직속 자식들은 여러분이 정의한 그리드에 맞춰 배치되는 아이템이 됩니다. display: grid만으로는 별다른 일이 일어나지 않으므로, 열과 행을 몇 개로 나눌지, 각각의 크기를 얼마로 할지도 함께 지정해야 합니다.

열은 grid-template-columns로, 행은 grid-template-rows로 정의합니다. 목록의 각 값이 하나의 트랙이고, 트랙은 하나의 열 또는 행을 의미합니다.

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;   /* 두 개의 열: 고정폭 하나, 그리고 나머지 */
  grid-template-rows: 80px 400px;     /* 두 개의 행: 짧은 것 하나, 긴 것 하나 */
}

어떤 요소에 display: grid를 지정하면 그 요소는 **그리드 컨테이너**가 되고, 그 직속 자식들은 여러분이 정의한 그리드 위에 배치되는 그리드 아이템이 됩니다. 이는 플렉스박스의 2차원 대응 개념이라 할 수 있는데, 플렉스박스는 한 번에 하나의 축을 따라 아이템을 배치합니다. 플렉스박스는 "이 한 줄(또는 한 열)의 아이템들이 공간을 어떻게 나눠야 할까?"를 묻고, 그리드는 "이 아이템들이 여러 행과 열로 이루어진 격자 안에서 어디에 놓여야 할까?"를 묻습니다.

트랙은 grid-template-columnsgrid-template-rows로 정의합니다. 각 값이 하나의 트랙, 즉 열이나 행을 나타내며, 값에는 고정 길이, 백분율, 그리고 다음 절에서 다룰 유연한 fr 단위를 섞어서 쓸 수 있습니다.

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;   /* 고정폭 사이드바, 유연한 메인 열 */
  grid-template-rows: auto 1fr auto;  /* 헤더는 콘텐츠 크기, 메인은 채우기, 푸터는 콘텐츠 크기 */
}

display: grid는 해당 요소에 **그리드 포매팅 컨텍스트**를 만듭니다. 즉 그 요소는 그리드 컨테이너가 되고, 직속 자식들은 그리드 아이템이 되며, 그 자식들에 적용되던 일반 흐름 규칙은 더 이상 적용되지 않습니다. 텍스트 노드는 익명 아이템으로 감싸지고, floatvertical-align 같은 속성은 아이템에 아무런 영향을 주지 못하게 되는데, 이제 배치는 그리드의 몫이기 때문입니다.

플렉스박스와의 차이는 차원성에 있으며, 이것이 가장 먼저 제대로 짚어야 할 부분입니다. 플렉스박스는 1차원입니다. 즉 아이템을 주축을 따라 분배하고 그 부수 효과로 줄바꿈이 일어나지만, 교차축 방향으로 콘텐츠를 격자에 맞춰 정렬하지는 않습니다. 그리드는 2차원입니다. 행과 열을 함께 정의하므로 아이템의 행 위치와 열 위치가 독립적으로 설정되고, 아이템들이 두 축 모두에서 동시에 맞춰집니다. 명시적 트랙은 grid-template-columnsgrid-template-rows로 정의하며, 각 값이 하나의 트랙을 만듭니다.

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;   /* 명시적 열 트랙 두 개 */
  grid-template-rows: auto 1fr auto;  /* 콘텐츠, 채우기, 콘텐츠 */
}

auto 키워드는 트랙을 콘텐츠 크기에 맞추고, 1fr은 남는 공간을 흡수합니다. 이 1fr의 동작 원리를 다음 절에서 이어서 다룹니다.

Juno그리드 컨테이너 어떤 요소에 display: grid를 추가하면 그 요소는 그리드 컨테이너가 되고, 직속 자식들이 그 안에 아이템으로 자리 잡습니다. 그런 다음 grid-template-columnsgrid-template-rows로 열과 행을 몇 개로 할지 정하는데, 트랙마다 값 하나씩 지정합니다. 이 트랙을 정의하기 전까지는 아무것도 정렬되지 않으므로, 이 작업이 언제나 첫 번째 단계입니다.
Juno그리드 컨테이너 플렉스박스는 한 번에 하나의 축을 따라 동작하고, 그리드는 행과 열을 함께 다루기 때문에 페이지 레이아웃에는 그리드가 더 자연스럽게 느껴집니다. display: grid를 지정한 다음 grid-template-columnsgrid-template-rows에 트랙을 나열하세요. 2차원으로 배치할 때는 그리드를, 한 줄이나 한 열만 정렬할 때는 플렉스박스를 사용하세요.
Juno그리드 컨테이너display: grid는 그리드 포매팅 컨텍스트를 만들기 때문에, 자식들은 더 이상 일반 흐름을 따르지 않고 float와 vertical-align은 조용히 아무 영향도 미치지 않게 됩니다. 플렉스박스와의 진짜 차이는 차원성입니다. 플렉스는 한 축을 따라 분배하고, 그리드는 두 축 모두에 동시에 배치합니다. 행과 열 위치가 둘 다 의미 있다면 그리드를, 한 축만 의미 있다면 플렉스를 선택하세요.

유연한 트랙

고정 픽셀 열도 괜찮지만, 대부분의 레이아웃은 공간을 균등하게 나눠 가지면서 화면 크기에 맞춰 늘어나는 열을 원합니다. 바로 그런 용도로 쓰는 것이 **fr 단위**입니다. 1fr은 남는 공간의 몫 하나를 의미하므로, 1fr씩 세 개의 열이 있으면 컨테이너를 3분의 1씩 나눠 갖습니다.

css
.gallery {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;   /* 동일한 크기의 세 열 */
}

1fr을 세 번 타이핑하는 건 번거로우니, repeat()가 대신 써줍니다. 그리고 gap은 트랙 사이의 간격을 지정해주므로, 아이템마다 마진을 일일이 넣을 필요가 없습니다.

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* 위와 같은 동일한 크기의 세 열 */
  gap: 16px;                               /* 행과 열 사이의 간격 */
}

fr 단위는 고정 크기와 간격을 제외한 후 컨테이너에 남는 공간의 몫을 나타냅니다. 1fr씩 세 열이 있으면 각각 3분의 1을 균등하게 가져가고, 2fr 1fr 쌍이면 공간을 2대1로 나눠 갖습니다. fr은 남는 공간을 나누므로, 고정 길이로는 할 수 없는 방식으로 컨테이너가 늘어나거나 줄어도 열의 비율이 유지됩니다.

트랙 목록을 읽기 쉽게 만들어주는 도우미가 두 가지 있습니다. repeat(3, 1fr)1fr 1fr 1fr로 확장되고, gap은 트랙 사이의 여백을 한 속성으로 지정합니다(다르게 지정하고 싶다면 row-gapcolumn-gap을 쓸 수 있습니다).

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* 동일한 크기의 세 열 */
  gap: 16px;                               /* 16px 여백, 행과 열 모두 */
}

여백은 아이템에 마진을 주는 게 아니라 gap으로 지정합니다. gap은 트랙 사이에만 적용되고 바깥 가장자리에는 절대 적용되지 않기 때문에, 그리드는 컨테이너에 딱 맞게 붙으면서 아이템 사이는 균등한 간격을 유지합니다.

fr 단위는 **유연한 길이**입니다. 고정 크기 트랙, 콘텐츠 크기로 정해지는 트랙, 그리고 간격까지 모두 계산하고 남은 컨테이너의 여유 공간에서 그 몫을 나타냅니다. 2fr 1fr 1fr 트랙 목록이라면 첫 번째 열이 여유 공간의 절반을, 나머지 두 열이 각각 4분의 1을 가져갑니다. 여기서 미묘한 점은 fr여유 공간을 분배하는 것이지 전체 너비를 분배하는 게 아니라는 것입니다. 그래서 넓은 콘텐츠를 담은 트랙은 별도로 제한하지 않으면 자기 몫의 fr을 넘어서 밀고 나갈 수 있는데, 이때 마지막 절에서 다룰 minmax()가 필요해집니다.

repeat()는 반복되는 트랙을 짧게 쓰는 방법입니다. repeat(3, 1fr)1fr 1fr 1fr과 같고, 조합도 가능해서 repeat(2, 200px 1fr)은 네 개의 트랙이 됩니다. gap(grid-gap의 현재 명칭)은 트랙 사이에만 여백을 지정하고 그리드 바깥쪽에는 절대 적용되지 않으므로, 컨테이너 자체의 패딩과 충돌하지 않습니다.

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* 동일한 크기의 세 열 */
  gap: 16px 24px;                          /* 행 간격 16px, 열 간격 24px */
}

gap에 값을 두 개 쓸 때는 행 간격이 먼저, 열 간격이 나중이라는 점에 주의하세요. 값을 하나만 쓰면 양쪽 모두에 적용됩니다.

Juno유연한 트랙1fr 하나는 남는 공간의 몫 하나를 의미하므로, 1fr 1fr 1fr이면 동일한 크기의 열 세 개가 나옵니다. 같은 값을 계속 반복해서 타이핑하지 않으려면 repeat(3, 1fr)을 쓰고, 트랙 사이의 간격에는 gap을 쓰세요. fr이 이해되고 나서부터는 아무리 더해도 딱 맞지 않던 백분율을 더 이상 쓰지 않게 됐습니다.
Juno유연한 트랙fr은 컨테이너의 남는 공간을 나누기 때문에, 페이지 크기가 바뀌어도 비율이 맞춰진 열들은 계속 비율을 유지합니다. 트랙 목록을 짧게 유지하려면 repeat()을 쓰고, 아이템마다 마진을 주는 대신 여백에는 gap을 쓰세요. gap은 트랙 사이에만 적용되고 바깥 가장자리에는 적용되지 않는다는 점을 기억하세요. 보통은 정확히 그게 원하는 동작입니다.
Juno유연한 트랙fr은 전체 너비가 아니라 남는 공간을 나누므로, 넓은 콘텐츠가 있는 트랙은 minmax()로 제한하기 전까지 자기 몫을 넘쳐버릴 수 있습니다. repeat()은 조합할 수 있어서 repeat(2, 200px 1fr)은 네 개의 트랙이 됩니다. 그리고 값이 두 개인 gap은 행 간격이 먼저, 열 간격이 나중인데, 시계방향 순서의 축약형과 같다고 생각하는 사람들이 자주 헷갈리는 부분입니다.

아이템 배치하기

기본적으로 각 아이템은 순서대로 다음 빈 셀에 하나씩 들어갑니다. 아이템이 여러 셀에 걸쳐 있게 하려면 grid-columngrid-row로 지정합니다. 트랙 사이의 선은 1부터 번호가 붙으므로, grid-column: 1 / 3은 "1번 선에서 시작해서 3번 선에서 끝난다"는 뜻이 되어 두 개의 열을 차지합니다.

css
.featured {
  grid-column: 1 / 3;   /* 1번 열 선부터 3번 선까지, 두 열 너비 차지 */
}

선을 일일이 세고 싶지 않다면, span으로 아이템이 놓인 자리부터 몇 개의 셀을 차지할지 말할 수 있습니다.

css
.featured {
  grid-column: span 2;   /* 이 아이템이 놓인 자리부터 두 열을 차지 */
}

그리드 배치는 그리드 선, 즉 트랙 사이와 바깥에 놓인 번호가 붙은 선으로 표현됩니다. 세 개의 열로 이루어진 그리드에는 1부터 4까지 네 개의 열 선이 있습니다. grid-column: 1 / 3은 아이템을 1번 선부터 3번 선까지 놓아 첫 두 열에 걸치게 하고, grid-row는 수직 방향으로 같은 역할을 합니다. span 키워드는 선을 셀 필요를 없애줍니다. grid-column: span 2는 아이템이 놓인 자리부터 두 열을 차지합니다.

페이지 전체 레이아웃을 만들 때는 선을 세는 것보다 영역에 이름을 붙이는 방식이 더 읽기 좋습니다. grid-template-areas를 쓰면 레이아웃을 이름 붙인 셀들의 집합으로 그려낸 다음, 각 아이템을 그 이름에 배정할 수 있습니다.

css
.page {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-areas:
    "sidebar header"
    "sidebar main";     /* 이름을 반복해서 사이드바가 두 행에 걸치게 함 */
}

.page > header { grid-area: header; }
.page > aside  { grid-area: sidebar; }
.page > main   { grid-area: main; }

배치는 그리드 선, 즉 모든 트랙 둘레에 번호가 붙은 경계선을 기준으로 이루어집니다(트랙이 n개인 축에는 n + 1개의 선이 있습니다). grid-column: 1 / 3은 시작 열 선과 끝 열 선을 지정해서 그 사이의 트랙에 걸치게 하고, grid-column: span 2는 시작 지점을 고정하지 않고 걸치는 폭만 지정해서 자동 배치 알고리즘이 놓일 자리를 스스로 정하게 합니다. 음수 선 번호는 끝에서부터 셈하므로, grid-column: 1 / -1은 열 개수가 몇이든 항상 전체 너비를 차지하는데, 이는 화면 전체 폭을 채우는 행을 안정적으로 만드는 방법입니다.

grid-template-areas는 셀에 이름을 붙여서 선 번호가 아니라 이름으로 아이템을 배치할 수 있게 해줍니다. 각 문자열이 한 행이고, 각 토큰이 하나의 셀이며, 같은 토큰을 여러 셀에 반복하면 하나의 아이템이 그 셀들에 걸치게 됩니다. 공백으로 정렬된 이 블록 자체가 레이아웃을 보여주는 읽기 좋은 그림이 되기도 합니다.

css
.page {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "sidebar header"
    "sidebar main";     /* 사이드바가 첫 번째 열의 두 행 모두를 차지 */
}

.page > aside { grid-area: sidebar; }

두 가지 규칙을 지켜야 합니다. 모든 행 문자열은 셀의 개수가 같아야 하고, 하나의 이름에 해당하는 셀들은 반드시 꽉 찬 직사각형을 이루어야 합니다. 그렇지 않으면 선언 전체가 유효하지 않아 무시됩니다. . 토큰은 의도적으로 비워두고 싶은 셀을 표시합니다.

Juno아이템 배치하기 아이템은 기본적으로 셀 하나씩 채우고, 여러 셀에 걸쳐 늘어나게 하려면 grid-column이나 grid-row를 씁니다. 선 번호는 1부터 시작하므로 grid-column: 1 / 3은 두 열을 차지하고, 세고 싶지 않다면 span 2를 쓰면 됩니다. 이것만 알아도 영역에 이름을 붙이기 전에 대부분의 레이아웃을 만들 수 있습니다.
Juno아이템 배치하기 그리드 선으로 아이템을 배치하세요. grid-column: 1 / 3은 두 열에 걸치고, span 2는 고정된 시작점부터 세지 않고도 같은 일을 합니다. 페이지 전체를 만들 때는 grid-template-areas로 영역에 이름을 붙이면 레이아웃을 한눈에 읽을 수 있어서, 선 번호를 손으로 추적하는 것보다 낫습니다. 이름을 여러 셀에 반복하면 그 영역이 그만큼 걸치게 됩니다.
Juno아이템 배치하기 선 번호는 음수도 쓸 수 있어서, grid-column: 1 / -1은 열이 몇 개든 상관없이 전체 너비를 차지합니다. 이것이 화면 전체를 채우는 안정적인 방법입니다. grid-template-areas를 쓸 때는 모든 행 문자열의 셀 개수가 같아야 하고 이름 붙인 영역은 반드시 꽉 찬 직사각형이어야 하며, 그렇지 않으면 선언 전체가 버려집니다. 일부러 셀을 비워두려면 . 토큰을 쓰세요.

미디어 쿼리 없이 반응형 그리드 만들기

카드 한 줄을 넓은 화면에서는 세 개씩, 태블릿에서는 두 개씩, 폰에서는 한 개씩 보여줘야 하는 상황이 있습니다. 브레이크포인트를 하나도 쓰지 않고 그리드만으로 이걸 해낼 수 있습니다. 핵심은 한 줄입니다.

css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}

안쪽부터 읽어보세요. minmax(200px, 1fr)은 각 열이 최소 200px, 최대는 공간의 몫 하나만큼이라는 뜻입니다. 그런 다음 auto-fit이 컨테이너에 들어갈 수 있는 만큼 그 열들을 최대한 채워 넣습니다. 화면이 넓으면 더 많은 열이 들어가고, 좁으면 더 적게 들어가면서 카드들이 스스로 다시 배치됩니다.

미디어 쿼리 하나 없이 카드를 다시 배치시키는 패턴은 repeat(auto-fit, minmax(200px, 1fr))입니다. 각 부분이 하나씩 역할을 맡습니다. minmax(200px, 1fr)200px보다 작아지지 않고 1fr 몫보다 커지지 않는 트랙을 정의합니다. auto-fit은 현재 너비에 들어갈 수 있는 만큼 그 트랙을 반복하므로, 열의 개수가 고정된 브레이크포인트가 아니라 컨테이너의 크기에 반응합니다.

css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}

200px이라는 최솟값이 실제로 제어할 수 있는 부분입니다. 이는 그리드가 열 개수를 줄이기 전까지 카드가 허용되는 가장 좁은 너비입니다. 이 방식은 반응형 디자인에서 다루는 유연한 기법들과 잘 어울리고, 보통 카드 그리드를 위해 따로 작성했을 미디어 쿼리를 대신하게 됩니다.

repeat(auto-fit, minmax(200px, 1fr))은 반응형 그리드의 정석 표현이며, 각 부분이 자기 역할을 확실히 합니다. minmax(min, max)는 하한과 상한을 가진 트랙을 정의합니다. minmax(200px, 1fr)200px 이하로 줄어들지 않고 여유 공간의 몫 하나를 넘어서 커지지도 않습니다. 이 200px 최솟값이 리플로우 임계값, 즉 그리드가 열 하나를 얻거나 잃는 너비를 결정합니다.

auto-fitauto-fill 중 어느 것을 선택할지가 알아둘 만한 부분입니다. 둘 다 컨테이너에 minmax() 트랙이 몇 개나 들어갈지 계산합니다. auto-fill은 남는 빈 트랙을 그리드에 그대로 남겨두므로, 카드가 절반만 채워진 줄이라도 열 너비가 그대로 유지됩니다. auto-fit은 그 빈 트랙을 너비 0으로 접어버리므로, 실제로 있는 아이템들이 늘어나 줄을 채웁니다.

css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));   /* 아이템이 늘어나 채운다 */
  gap: 16px;
}

한 가지 주의할 점이 있습니다. minmax(200px, 1fr)200px과 간격을 합친 것보다 좁은 컨테이너에서는 넘칠 수 있는데, 이 최솟값이 절대적인 하한이기 때문입니다. minmax(min(200px, 100%), 1fr)은 매우 작은 화면에서는 최솟값이 컨테이너 너비까지 내려갈 수 있게 해서 이 문제를 막아줍니다. 여러 기기에서 이 최솟값을 안정적으로 지정하는 방법은 크기 단위에서 길이 단위가 어떻게 계산되는지 다룹니다.

Juno미디어 쿼리 없이 반응형 그리드 만들기repeat(auto-fit, minmax(200px, 1fr))은 브레이크포인트 없이도 카드가 스스로 다시 배치되게 합니다. 각 열은 최소 200px, 최대 공간의 몫 하나이고, auto-fit이 들어갈 수 있는 만큼 채워 넣습니다. 200px을 바꾸면 나란히 놓이는 카드 개수가 달라집니다.
Juno미디어 쿼리 없이 반응형 그리드 만들기repeat(auto-fit, minmax(200px, 1fr)) 한 줄이 카드 그리드용 미디어 쿼리 여러 개를 대신합니다. 200px 최솟값이 조절 지점입니다. 그리드가 열 하나를 줄이기 전까지 카드가 얼마나 좁아질 수 있는지를 정하니까요. 진짜로 카드가 다시 배치되는 그리드라면, 브레이크포인트를 쓰기 전에 이 방법을 먼저 떠올리세요.
Juno미디어 쿼리 없이 반응형 그리드 만들기auto-fit은 빈 트랙을 접어서 실제 아이템이 늘어나 채우게 하고, auto-fill은 빈 트랙을 남겨서 빈 공간이 생깁니다. 이게 둘의 유일한 차이입니다. 오버플로 상황을 조심하세요. 고정된 200px 최솟값은 매우 좁은 컨테이너에서 넘칠 수 있으므로, minmax(min(200px, 100%), 1fr)이 더 안전한 최솟값입니다. 이 최솟값이 리플로우 지점을 결정하므로, 가장 작아도 괜찮은 카드 크기를 염두에 두고 정하세요.

명시적 그리드와 암시적 그리드

지금까지 다룬 것은 모두 명시적 그리드, 즉 grid-template-columnsgrid-template-rows에 직접 이름 붙인 트랙입니다. 아이템이 이 정의된 그리드를 벗어나 놓이면 브라우저가 그것들을 담을 트랙을 만들어내는데, 이렇게 만들어진 트랙들이 **암시적 그리드**를 이룹니다. 세 열, 한 행짜리 명시적 그리드에 네 번째 아이템을 추가하면 새로운 두 번째 행이 암시적으로 만들어지면서 시작됩니다. 암시적 트랙은 기본적으로 크기가 auto이므로, 따로 지정하지 않으면 암시적 행은 그 안의 콘텐츠 크기만큼만 높이를 갖습니다.

grid-auto-rows는 이런 암시적 행의 크기를 지정합니다(암시적 열은 grid-auto-columns가 담당합니다). 그러면 행이 몇 개나 생길지 예측할 수 없는 카드 그리드도 균등한 행 높이를 가질 수 있습니다.

css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* 명시적: 세 열 */
  grid-auto-rows: 240px;                   /* 암시적 행은 각각 240px */
  gap: 16px;
}

그런 다음 정렬 속성이 아이템과 트랙이 각 셀 안에서 어디에 자리 잡을지 결정합니다. justify-items는 행(인라인) 축을 따라 아이템을 정렬하고, align-items는 열(블록) 축을 따라 정렬하며, 각각 start, end, center, 또는 기본값이자 셀을 채우는 stretch를 받습니다. place-items는 둘을 합친 축약형으로, 블록 축이 먼저 옵니다.

css
.gallery {
  place-items: center;   /* align-items와 justify-items를 동시에 가운데로 정렬 */
}

minmax()는 콘텐츠 기반 키워드인 min-contentmax-content도 받습니다. min-content는 콘텐츠가 넘치지 않는 한도 안에서 트랙이 가질 수 있는 가장 작은 크기(대략 줄바꿈이 불가능한 가장 긴 단어의 너비)이고, max-content는 줄바꿈을 강제하지 않을 때 콘텐츠가 원하는 크기입니다. minmax(min-content, max-content) 같은 트랙은 그 범위 안에서 콘텐츠 크기에 맞춰집니다. 그리고 subgrid는 중첩된 그리드가 부모의 트랙 선을 물려받게 해주므로, 자식 그리드의 열이 자기 것을 새로 정의하는 대신 바깥 그리드와 맞춰집니다.

그리드와 플렉스 중 무엇을 선택할지에 대해서는 다음과 같은 명확한 기준이 있습니다. 콘텐츠를 한 축으로 배치하고 그 결과로 줄바꿈이 일어나게 하고 싶다면 플렉스박스를 쓰세요. 예를 들면 내비게이션 바, 태그 한 줄, 툴바 같은 경우입니다. 두 축 모두에서 맞춰야 하는 행과 열로 콘텐츠를 배치해야 한다면 그리드를 쓰세요. 예를 들면 페이지 뼈대, 카드 갤러리, 레이블과 필드가 정렬된 폼 같은 경우입니다. 이 둘은 잘 조합되어서, 그리드 셀 안에 플렉스 컨테이너를 두는 경우가 흔하고, 이 조합이 여러분이 만들게 될 대부분의 레이아웃을 아우릅니다.

Juno명시적 그리드와 암시적 그리드 직접 선언한 트랙은 명시적 그리드이고, 넘치는 아이템을 담기 위해 브라우저가 추가하는 것은 암시적 그리드입니다. 이 추가된 트랙들은 grid-auto-rowsgrid-auto-columns로 지정하지 않는 한 auto 크기를 갖습니다. 정렬은 justify-itemsalign-items가 담당하고, place-items가 그 축약형이며 기본값은 stretch입니다. 판단 기준은 이렇습니다. 한 축이고 줄바꿈이 필요하면 플렉스박스, 두 축 모두 맞춰야 하면 그리드이며, 둘은 서로 잘 중첩됩니다.