とほほのGrid入門

目次

グリッドとは

基本的グリッド

縦横のセルを定義し、左上から順番にアイテムを並べていく方式です。display: grid はこの要素がグリッドの親コンテナであることを示します。grid プロパティはグリッドコンテナ内のセルを定義します。下記の例では縦方向に 2rem 2rem の2行、横方向に 4rem 4rem 4rem の3列、6個のセルを定義しています。

CSS
.container-grid {
  display: grid;
  grid: 2rem 2rem / 4rem 4rem 4rem;
}
HTML
<div class="container-grid">
  <div class="box">A</div>
  <div class="box">B</div>
  <div class="box">C</div>
  <div class="box">D</div>
  <div class="box">E</div>
  <div class="box">F</div>
</div>
HTML
A
B
C
D
E
F

方向指定

grid-auto-flow はアイテムをセルに並べていく方向を指定します。column を指定すると行が埋まると、列を増やしていきます。

CSS
.container-grid-with-flow {
  display: grid;
  grid: 2rem 2rem / 4rem 4rem 4rem;
  grid-auto-flow: column;
}
HTML
A
B
C
D
E
F

名前付きエリア

grid でエリアに名前を付け、アイテムに配置先のエリア名を指定する方式です。下記の例では、上部にヘッダ(header)、下部にフッタ(footer)を配置、中央を メニュー(menu)、メイン(main)、サイドバー(side) の3エリアに分割し、子アイテムをエリア名でそれぞれの場所に配置しています。

CSS
.container-named-area {
  display: grid;
  grid: "header header header"
        "menu   main   side"
        "footer footer footer";
  .header { grid-area: header; }
  .menu   { grid-area: menu; }
  .main   { grid-area: main; }
  .side   { grid-area: side; }
  .footer { grid-area: footer; }
}
HTML
<div class="container-named-area">
  <div class="box header">Header</div>
  <div class="box menu">Menu</div>
  <div class="box main">Main</div>
  <div class="box side">Side</div>
  <div class="box footer">Footer</div>
</div>
表示
Header
Main
Side

名前付きエリアの横幅・高さ指定

grid でエリア名を指定する際に、エリアの高さ、横幅を指定することができます。下記の例ではエリアの高さを 2rem, 4rem, 2rem、横幅を 4rem, 16rem, 4rem に指定しています。高さに auto を指定すると最小の高さ、横幅に auto を指定すると最大の横幅となります。

CSS
.container-named-area-with-length {
  display: grid;
  grid: "header header header" 2rem
        "menu   main   side"   4rem
        "footer footer footer" 2rem
      /  4rem   16rem  4rem;
  .header { grid-area: header; }
  .menu   { grid-area: menu; }
  .main   { grid-area: main; }
  .side   { grid-area: side; }
  .footer { grid-area: footer; }
}
HTML
<div class="container-named-area-with-length">
  <div class="box header">Header</div>
  <div class="box menu">Menu</div>
  <div class="box main">Main</div>
  <div class="box side">Side</div>
  <div class="box footer">Footer</div>
</div>
表示
Header
Main
Side

エリア名と高さ・横幅を個別に指定

grid-template-areas, grid-template-rows, grid-template-columns はエリア名、高さ、横幅を個別に指定します。

CSS
.container-named-area-with-length-2 {
  display: grid;
  grid-template-areas:
        "header header header"
        "menu   main   side"
        "footer footer footer";
  grid-template-rows: 2rem 4rem 2rem;
  grid-template-columns: 4rem 16rem 4rem;
  .header { grid-area: header; }
  .menu   { grid-area: menu; }
  .main   { grid-area: main; }
  .side   { grid-area: side; }
  .footer { grid-area: footer; }
}
HTML
<div class="container-named-area-with-length-2">
  <div class="box header">Header</div>
  <div class="box menu">Menu</div>
  <div class="box main">Main</div>
  <div class="box side">Side</div>
  <div class="box footer">Footer</div>
</div>
表示
Header
Main
Side

デフォルトの高さと横幅

grid-auto-rows, grid-auto-columns はセルの高さや横幅が指定されない場合のデフォルトサイズを指定します。

CSS
.container-with-default-size {
  display: grid;
  grid-template-areas:
      "itemA itemB itemC"
      "itemD itemE itemF";
  grid-auto-rows: 2rem;
  grid-auto-columns: 10rem;
  .itemA { grid-area: itemA; }
  .itemB { grid-area: itemB; }
  .itemC { grid-area: itemC; }
  .itemD { grid-area: itemD; }
  .itemE { grid-area: itemE; }
  .itemF { grid-area: itemF; }
}
HTML
<div class="container-with-default-size">
  <div class="box itemA">A</div>
  <div class="box itemB">B</div>
  <div class="box itemC">C</div>
  <div class="box itemD">D</div>
  <div class="box itemE">E</div>
  <div class="box itemF">F</div>
</div>
表示
A
B
C
D
E
F

開始ライン・終了ライン

アイテムの開始ラインと終了ライン番号を指定する方式です。セル番号ではなく、線の番号で指定します。grid-area には、縦方向の開始線 / 横方向の開始線 / 縦方向の終了線 / 横方向の終了線 を指定します。

CSS
.container-line-number {
  display: grid;
  grid: 2rem 2rem / 4rem 4rem 4rem 4rem;
  .itemA { grid-area: 1 / 1 / 3 / 2; }
  .itemB { grid-area: 1 / 2 / 2 / 4; }
  .itemC { grid-area: 2 / 2 / 3 / 3; }
  .itemD { grid-area: 2 / 3 / 3 / 4; }
  .itemE { grid-area: 1 / 4 / 3 / 5; }
}
HTML
<div class="container-line-number">
  <div class="box itemA">A</div>
  <div class="box itemB">B</div>
  <div class="box itemC">C</div>
  <div class="box itemD">D</div>
  <div class="box itemE">E</div>
</div>
表示
A
B
C
D
E

名前付きライン

下記の様に [...] でラインに好みの名前を付けることができます。[head-top] はヘッダエリアの上部のライン、[head-bottom] はヘッダエリアの下部のラインを、[x1]~[x4] は左から1本目~4本目のラインの名前を意味します。

CSS
.container-named-line {
  display: grid;
  grid:
    [head-top] "head      head      head" 2rem [head-bottom]
    [body-top] "menu      main      side" 2rem [body-bottom]
    [foot-top] "foot      foot      foot" 2rem [foot-bottom]
        / [x1]  4rem [x2] 4rem [x3] 4rem [x4];
  .head { grid-area: head-top / x1 / head-bottom / x4; }
  .menu { grid-area: body-top / x1 / body-bottom / x2; }
  .main { grid-area: body-top / x2 / body-bottom / x3; }
  .side { grid-area: body-top / x3 / body-bottom / x4; }
  .foot { grid-area: foot-top / x1 / foot-bottom / x4; }
}
HTML
<div class="container-named-line">
  <div class="box head">Header</div>
  <div class="box menu">Menu</div>
  <div class="box main">Main</div>
  <div class="box side">Side</div>
  <div class="box foot">Footer</div>
</div>
表示
Header
Main
Side
Footer

ギャップ(gap)

gap により、アイテム間のギャップ(隙間)を指定することができます。下記の例では、縦方向に 1rem、横方向に 4rem のギャップを指定しています。

CSS
.container-gap {
  display: grid;
  grid: 2rem 2rem / 3rem 3rem 3rem;
  gap: 1rem 4rem;
}
HTML
<div class="container-gap">
  <div class="box">A</div>
  <div class="box">B</div>
  <div class="box">C</div>
  <div class="box">D</div>
  <div class="box">E</div>
  <div class="box">F</div>
</div>
表示
A
B
C
D
E
F

オートフロー(auto-flow)

高さまたは横幅に auto-flow をつけると、その後の数値を無限回繰り返すのと同じ動作になります。下記の例では、2rem 2rem / 2rem 4rem 2rem 4rem 2rem 4rem... を無限回繰り返します。auto-flow は高さか横幅かどちらか一方に指定できます。

CSS
.container-auto-flow {
  display: grid;
  grid: 2rem 2rem / auto-flow 2rem 4rem;
}

スパン(span)

span を指定すると N 個分のアイテムの高さ・横幅を指定することができます。

CSS
.container-span {
  display: grid;
  grid: auto-flow 2rem / 2rem 2rem 2rem 2rem 2rem 2rem;
}
.span-3 {
  grid-column: span 3;
}
HTML"
<div class="container-span">
  <div class="box">A</div>
  <div class="box span-3">B</div>
  <div class="box">C</div>
  <div class="box">D</div>
</div>
表示
A
B
C
D

オート(auto)

auto を横幅に指定すると最大長に、高さに指定すると最低長となります。

CSS
.container-auto {
  display: grid;
  grid: 3rem auto 3rem / 3rem auto 3rem;
}
HTML
<div class="container-auto">
  <div class="box">A</div>
  <div class="box">B</div>
  <div class="box">C</div>
  <div class="box">D</div>
  <div class="box">E</div>
  <div class="box">F</div>
  <div class="box">G</div>
  <div class="box">H</div>
  <div class="box">I</div>
</div>
表示
A
B
C
D
E
F
G
H
I

フラクションサイズ(fr)

グリッドの長さ指定ではフラクションサイズ(fr)という単位を用いることができます。fraction は「分数」を意味します。下記では横幅の長さを、最大横幅の 1/10, 2/10, 3/10, 4/10 で指定しています。

.container-fr {
  display: grid;
  grid: 2rem / 1fr 2fr 3fr 4fr;
}
HTML
<div class="container-fr">
  <div class="box">A</div>
  <div class="box">B</div>
  <div class="box">C</div>
  <div class="box">D</div>
</div>
表示
A
B
C
D

最小最大(minmax)

minmax(min, max) は最小値と最大値を指定します。下記の例で Bアイテムは、最小でも 30rem、最大でも 40rem の横幅に制限されます。

CSS
.container-minmax {
  display: grid;
  grid: 2rem / 2rem minmax(30rem, 40rem) 2rem;
}
HTML
<div class="container-minmax">
  <div class="box">A</div>
  <div class="box">B</div>
  <div class="box">C</div>
</div>
表示
A
B
C

最大コンテント(max-content)

max-content は子アイテムの中で一番大きなアイテムの長さを示します。アイテムの中身がテキストの場合、アイテムの長さはテキストを改行無しで表示した場合のテキストの長さとなります。下記の例では1列目の横幅を、一番長いテキストの横幅にそろえています。

CSS
.container-max-content {
  display: grid;
  grid-template-columns: max-content auto;
}
HTML
<div class="container-max-content">
  <div class="box">Short text</div>
  <div class="box">X</div>
  <div class="box">Very very long long text</div>
  <div class="box">Y</div>
  <div class="box">Middle length text</div>
  <div class="box">Y</div>
</div>
表示
Short text
X
Very very long long text
Y
Middle length text
Z

最小コンテント(min-content)

min-content は、子アイテムをなるべく小さく表示します。アイテムの中身がテキストの場合は、一番長い単語の長さになります。

CSS
.container-min-content {
  display: grid;
  grid-template-columns: min-content auto;
}
HTML
<div class="container-min-content">
  <div class="box">Congratulations is a long word.</div>
  <div class="box">X</div>
  <div class="box">Short text.</div>
  <div class="box">Y</div>
  <div class="box">Short text.</div>
  <div class="box">Z</div>
</div>
表示
Congratulations is a long word.
X
Short text.
Y
Short text.
Z

フィットコンテント(fit-content())

fit-content(length) は基本的には length の長さとなりますが、min-content 以上 man-content 以下の範囲に制限されます。下記の例で、コンテナの横幅を広げたり狭めたりしても、左側のアイテムの横幅は、max-content(テキストを改行しない場合の横幅)より長くなることはなく、min-content(テキストを最大限改行した場合の横幅)より短くなることはありません。min-contentmax-content の間は 50% となります。

CSS
.container-fit-content {
  padding: .5rem;
  border: 1px solid gray;
  overflow: hidden;
  resize: horizontal;
  display: grid;
  grid: 3rem / fit-content(50%) auto;
  resize: both;
}
HTML
<div class="container-fit-content">
  <div class="box">Congratulations is a long word. </div>
  <div class="box">X</div>
</div>
表示
Congratulations is a long word.
X

リピート(repeat())

repeat(times, length)lengthtimes 回指定します。repeat(3, 10rem) は 10rem 10rem 10rem と同じ意味を持ちます。

CSS
.container-repeat {
  display: grid;
  grid: 2rem / 2rem repeat(3, 10rem) 2rem;
  padding: .5rem;
}
HTML
<div class="container-repeat">
  <div class="box">A</div>
  <div class="box">B</div>
  <div class="box">C</div>
  <div class="box">D</div>
  <div class="box">E</div>
</div>
表示
A
B
C
D
E

timesauto-fill を指定すると length で指定した長さのアイテムをコンテナ一杯まで並べます。auto-fit は minmax(min, max) と組み合わせることで min 以上 max 以下のアイテムをコンテナの幅いっぱいに並べることができます。下記の例で枠の横幅を変更して振る舞いを確認してみてください。

CSS
.container-repeat-auto-fill {
  display: grid;
  grid-template-columns: repeat(auto-fill, 6rem);
  padding: .5rem;
}
.container-repeat-auto-fit {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr));
  padding: .5rem;
}
HTML
<div class="container-repeat-auto-fill">
  <div class="box">A</div>
  <div class="box">B</div>
  <div class="box">C</div>
  <div class="box">D</div>
  <div class="box">E</div>
</div>
<div class="container-repeat-auto-fit">
  <div class="box">A</div>
  <div class="box">B</div>
  <div class="box">C</div>
  <div class="box">D</div>
  <div class="box">E</div>
</div>
表示
A
B
C
D
E
A
B
C
D
E

密集(dense)

dense は「密集」という意味を持ちます。大きさの異なるアイテムを詰めていく際、通常であれば直前のアイテムの次の位置に詰めますが、dense を指定すると空きスペースがあればそこに埋めます。

CSS
.container-no-dense {
  display: grid;
  grid: 2rem 2rem 2rem 2rem / 2rem 2rem 2rem;
}
.container-dense {
  display: grid;
  grid: auto-flow 2rem 2rem 2rem 2rem / 2rem 2rem 2rem;
  grid-auto-flow: dense;
}
.big {
  grid-row: span 2; grid-column: span 2;
}
HTML
<b>no dense</b>
<div class="container-no-dense">
  <div class="box grid-item">A</div>
  <div class="box grid-item big">B</div>
  <div class="box grid-item big">C</div>
  <div class="box grid-item">D</div>
</div>
<b>dense</b>
<div class="container-dense">
  <div class="box grid-item">A</div>
  <div class="box grid-item big">B</div>
  <div class="box grid-item big">C</div>
  <div class="box grid-item">D</div>
</div>
表示
no dense
A
B
C
D
dense
A
B
C
D

サブグリッド(subgrid)

2023年9月の Chrome 117 がリリースされ、主要モダンブラウザでサブグリッド(subgrid)がサポートされました。下記の例ではコンテナの中にアイテムとしてカード(card)を表示しています。さらに、カードをサブグリッドとして扱い、カード内のタイトルなどの子要素をサブアイテムとして扱っています。これにより、各カード間のタイトルの高さをそろえたりすることが可能となります。下記の例で 「subgrid指定」のチェックボックスを On/Off して、サブグリッド指定時と未指定時の振る舞いを確認してください。

CSS
.container-subgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, 10rem);
  gap: .5rem 2rem;
  padding: .5rem;
}
.card {
  display: grid;
  grid-template-rows: subgrid;
  border: 1px solid #999;
  grid-row: span 2;
  padding: .5rem;
}
.card-title {
  font-weight: bold;
  font-size: 120%;
}
.card-pict {
  height: 5rem;
  text-align: center;
  border: 1px solid #999;
}
HTML
<div class="container-subgrid">
  <div class="card">
    <div class="card-title">Short Title</div>
    <div class="card-pict">Picture</div>
  </div>
  <div class="card">
    <div class="card-title">Long Long Long Title</div>
    <div class="card-pict">Picture</div>
  </div>
  <div class="card">
    <div class="card-title">Very Very Very Very Long Long Long Long Long Title</div>
    <div class="card-pict">Picture</div>
  </div>
</div>
表示
Short Title
Picture
Long Long Long Title
Picture
Very Very Very Very Long Long Long Long Long Title
Picture

グリッドレイアウト

グリッドのレイアウトを指定するものに下記があります。詳細は 「フレックス・グリッドのレイアウト」を参照してください。

CSS
.container-layout {
  display: grid;
  grid: 2rem / auto-flow 10rem;
  margin-bottom: 1rem;
  border: 1px solid #ccc;
  background-color: #eee;
}
.cjc-left { justify-content: left; }
.cjc-center { justify-content: center; }
.cjc-right { justify-content: right; }
.cjc-space-between { justify-content: space-between; }
.cjc-space-around { justify-content: space-around; }
.cjc-space-evenly { justify-content: space-evenly; }
HTML
<div class="container-layout cjc-xxxx">
  <div class="box">xxxx</div>
  <div class="box">xxxx</div>
  <div class="box">xxxx</div>
</div>
表示
left
left
left
center
center
center
right
right
right
space-between
space-between
space-between
space-around
space-around
space-around
space-evenly
space-evenly
space-evenly

CSSプロパティ

親コンテナに指定するプロパティには下記があります。

display: grid
この要素がグリッドのコンテナであることを示します。
grid: ...
grid-template, grid-template-row, grid-template-columns, grid-auto-row, grid-auto-columns をまとめて指定します。
grid-template: ...
grid-template-rows, grid-template-columns をまとめて指定します。
grid-template-arias: ...
エリア名を定義します。
grid-template-rows, grid-template-columns: ...
アイテムの高さ、横幅、線名を指定します。
grid-auto-flow: ...
アイテムを並べる方向、および、アイテムの密集度を指定します。
grid-auto-rows, grid-auto-columns: ...
アイテムのデフォルトの高さ、横幅を指定します。

子アイテムに指定するプロパティには下記があります。

grid-area: ...
子アイテムに指定して、grid-row, grid-column をまとめて指定します。
grid-row: ...
子アイテムに指定して、grid-row-start, grid-row-end をまとめて指定します。
grid-column: ...
子アイテムに指定して、grid-column-start, grid-column-end をまとめて指定します。
grid-row-start, grid-row-end, grid-column-start, grid-column-end: ...
子アイテムに指定して、縦方向の開始ライン、横方向の開始ライン、縦方向の終了ライン、横方向の終了ラインを、ライン番号またはライン名で指定します。

文法

grid:
    <grid-template>
  | <grid-template-rows> / [ auto-flow && dense? ] <grid-auto-columns>?
  | [ auto-flow && dense? ] <grid-auto-rows>? / <grid-template-columns>

grid-template:
    none
  | [ <grid-template-rows> / <grid-template-columns> ]
  | [ <line-names>? <string> <track-size>? <line-names>? ]+ [ / <explicit-track-list> ]?

grid-template-areas:
    none
  | <string>+

grid-template-rows, grid-template-columns:
    none
  | <track-list>
  | <auto-track-list>
  | subgrid <line-name-list>?

grid-auto-flow:
    [ row | column ] || dense

grid-auto-rows, grid-auto-columns:
    <track-size>+

grid-aria:
    <grid-line> [ / <grid-line> ]{0,3}

grid-row, grid-column:
    <grid-line> [ / <grid-line> ]?

grid-row-start, grid-column-start, grid-row-end, grid-column-end:
    <grid-line>

<track-list>          = [ <line-names>? [ <track-size> | <track-repeat> ] ]+ <line-names>?
<auto-track-list>     = [ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>? <auto-repeat>
                        [ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>?
<explicit-track-list> = [ <line-names>? <track-size> ]+ <line-names>?
<line-name-list>      = [ <line-names> | <name-repeat> ]+
<track-size>          = <track-breadth>
                      | minmax( <inflexible-breadth> , <track-breadth> )
                      | fit-content( <length-percentage [0,∞]> )
<fixed-size>          = <fixed-breadth>
                      | minmax( <fixed-breadth> , <track-breadth> )
                      | minmax( <inflexible-breadth> , <fixed-breadth> )
<grid-line>           = auto
                      | <custom-ident>
                      | [ [ <integer [-∞,-1]> | <integer [1,∞]> ] && <custom-ident>? ]
                      | [ span && [ <integer [1,∞]> || <custom-ident> ] ]
<track-breadth>       = <length-percentage [0,∞]> | <flex [0,∞]> | min-content | max-content | auto
<inflexible-breadth>  = <length-percentage [0,∞]> | min-content | max-content | auto
<fixed-breadth>       = <length-percentage [0,∞]>
<line-names>          = '[' <custom-ident>* ']'
<track-repeat> = repeat( [ <integer [1,∞]> ] , [ <line-names>? <track-size> ]+ <line-names>? )
<auto-repeat>  = repeat( [ auto-fill | auto-fit ] , [ <line-names>? <fixed-size> ]+ <line-names>? )
<fixed-repeat> = repeat( [ <integer [1,∞]> ] , [ <line-names>? <fixed-size> ]+ <line-names>? )
<name-repeat>  = repeat( [ <integer [1,∞]> | auto-fill ], <line-names>+ )