EagleLand

CSS Grid Layout Moduleについて調べたメモ

Published at 2016-03-12

CSSによるレイアウトの問題はFlexboxでほとんどが解決されたと言って良いが、複雑なグリッドレイアウトを実現するためにCSS Grid Layout Moduleの策定が進められている。display: grid;ないしdisplay: inline-grid;といったように、displayプロパティに値が追加されており、それらが指定された要素はブロック要素またはインライン要素のように振る舞い、内包されるコンテンツがグリッドモデルに従ってレイアウトされる。

Chromeは50から、Firefoxは46から対応しているが、Chromeは現安定バージョンの49でもchrome://flags/Experimental Web Platform featuresを有効にすれば使える。

そんなdisplay: grid;について調べたメモ。

大まかな構造

display: grid;によって定義されるグリッド要素と、その子要素として配置されるセルから構成する。例えば、よくあるヘッダー・フッター・メインコンテンツ・サイドカラムがあるページ構造を作るとすると、次のようなHTMLとCSSになる。

<main>
  <header>Header</header>
  <article>Article</article>
  <aside>Aside</aside>
  <footer>Footer</footer>
</main>
main {
  display: grid;
  grid-template-rows: 50px 1fr 50px;
  grid-template-columns: 100px 1fr;
}

header {
  grid-row: 1 / 2;
  grid-column: 1 / 3;
}

aside {
  grid-row: 2 / 3;
  grid-column: 1 / 2;
}

article {
  grid-row: 2 / 3;
  grid-column: 2 / 3;
}

footer {
  grid-row: 3 / 4;
  grid-column: 1 / 3;
}

レイアウトは子要素の順序に依存しない

見ての通り、グリッド要素下のセル要素のgrid-rowgrid-columnによってどういった領域を占めるかが決定されるので、HTMLの記述順序は直接影響しない。

frとはなんぞ

1frという記述があるが、display: grid;が指定された要素に対して有効な単位で、要素内の可用領域のうち占める割合を表す。Flexboxのflex-growと同じような振る舞いをすると理解してもらえれば良さそう。

グリッドを定義する - grid-template-rowsgrid-template-columns

display: grid;を指定した要素に、行と列を定義するのがgrid-template-rowsgrid-template-columnsで、高さおよび横幅をそれぞれスペース区切りで指定する。

.grid {
  display: grid;
  grid-template-rows: 100px 50px;
  grid-template-columns: 100px 150px 50px;
}

これで2行×3列のグリッドが定義される。

セル領域の名前 - grid-template-areas

grid-template-rowsgrid-template-columnsによってグリッドの格子が定義されるが、生成されたセルにもgrid-template-areasプロパティで名前を付けることが可能。先程の2行×3列のグリッドのセルにそれぞれ名前をつけると以下のようになる。

.grid {
  display: grid;
  grid-template-rows: 100px 50px;
  grid-template-columns: 100px 150px 50px;
  grid-template-areas: 'area-a area-a area-b'
                       'area-c area-d area-d';
}

同じ名前をつけていると1つの領域として扱われる。

grid-template-*のショートハンド - grid-template

grid-template-rowsgrid-template-columnsgrid-template-areasは以下のようにまとめられる。

.grid {
  display: grid;
  grid-template-rows: 100px 50px;
  grid-template-columns: 100px 150px 50px;
  grid-template-areas: 'area-a area-a area-b'
                       'area-c area-d area-d';
}

区切り線の名前

ここで区切り線と言っているのはグリッドを構成するための上下左右のセル分割線のことで、セルが1つのときは上下に1本ずつ・左右に1本ずつ存在することになる。したがって、先程の2行×3列のグリッドであれば、行には3本・列には4本である。この区切り線の内包するセルの振る舞いを決める上でとても重要である。区切り線は以下のように採番される。

この区切り線には[name]のように名前をつけることができる。

.grid {
  display: grid;
  grid-template-rows: [row-a] 100px [row-b] 50px [row-c];
  grid-template-columns: [column-a] 100px [column-b] 150px [column-c] 50px [column-d];
  grid-template-areas: 'area-a area-a area-b'
                       'area-c area-d area-d';
}

セルの暗黙的生成 - grid-auto-rowsgrid-auto-columns

grid-templateを使うことでセルが明示的に定義されるが、後述のgrid-rowgrid-columnによって、定義されていないセルを指定された場合にも暗黙的にセルが配置される。その時に、セルの縦横サイズを決定するのがgrid-auto-rowsgrid-auto-columnsである。

.grid {
  display: grid;
  grid-template-rows: [row-a] 100px [row-b] 50px [row-c];
  grid-template-columns: [column-a] 100px [column-b] 150px [column-c] 50px [column-d];
  grid-template-areas: 'area-a area-a area-b'
                       'area-c area-d area-d';
  grid-auto-rows: 50px;
  grid-auto-columns: 50px;
}

セルの自動配置 - grid-auto-flow

後述のセルのレイアウトプロパティによって、位置が決定しないグリッド配下の要素がどのように配置されるかを決定するのがgrid-auto-flowで、行列を追加して作られた空きセル対して要素を埋めていく。セルが満タンの場合に、行追加を行うのがrow、列追加を行うのがcolumn、空きセルへの配置を試みるのがdense

denseの使いドコロが難しそうというか、利用シーンが今のところ浮かばない。

セル同士の間隔 - grid-column-gapgrid-row-gap

セル同士の間隔を指定するには、グリッド要素のgrid-column-gapgrid-row-gapプロパティに値を指定する。初期値は0になっているのでセル同士は吸着しているが、グリッドそのものにガターを明示するにはこれに任意の値を指定すれば良い。

.grid {
  display: grid;
  grid-template-rows: [row-a] 100px [row-b] 50px [row-c];
  grid-template-columns: [column-a] 100px [column-b] 150px [column-c] 50px [column-d];
  grid-template-areas: 'area-a area-a area-b'
                       'area-c area-d area-d';
  grid-row-gap: 10px;
  grid-column-gap: 20px;
}

grid-*-gapのショートハンド - grid-gap

grid-gapはショートハンドで、grid-row-gap: 10px; grid-column-gap: 20px;grid-gap: 10px 20px;と等価になる。

grid-*のショートハンド - grid

grid-templategrid-auto-*grid-gapを一括して指定するにはgridプロパティを使う。grid: [grid-template] [grid-auto-flow] [grid-auto-rows] / [grid-auto-columns] [grid-gap];の順に指定する。

linear-gradient: ...;みたいな空気を感じる。

セルを定義する - grid-column-startgrid-column-endgrid-row-startgrid-row-end

分割されたグリッドに要素を配置するには、要素が行列それぞれの どの区切り線からどの区切り線まで を占めるかを指定する。要素がセルとして占める範囲を、grid-row-startgrid-row-endで行方向の区切り線番号を、grid-column-startgrid-column-endで列方向の区切り線番号を指定する。

.cell {
  grid-row-start: 2;
  grid-column-start: 2;
  grid-row-end: 3;
  grid-column-end: 4;
}

これで.cellが指定された要素は、コンテナのグリッド要素の 2行目から2行目まで2列目から3列目まで を占めることになる。

grid-*-startgrid-*-endのショートハンド - grid-rowgrid-columngrid-area

開始位置と終了位置の指定は、ショートハンドのgrid-rowgrid-columnを使ってまとめることもできる。まとめる場合は、数値をスラッシュ区切りで指定する。先程の.cellをこれらで書き換えると以下のようになる。

.cell {
  grid-row: 2 / 3;
  grid-column: 2 / 4;
}

また、開始と終了の4点を指定できればいいので、1度に指定できるようにgrid-areaというプロパティも存在する。注意したいのは順序で、grid-row-startgrid-column-startgrid-row-endgrid-column-endの順に指定する。先程の.cellgrid-areaで書き換えると以下のようになる。

.cell {
  /* grid-row-start / grid-column-start / grid-row-end / grid-column-end */
  grid-area: 2 / 2 / 3 / 4;
}

区切り線番号のマイナス値

区切り線番号は起点を右下にして、マイナスで指定する方法もある。2行×3列のグリッドであれば、下から数えると-1、-2、-3であり、右から数えると-1、-2、-3、-4ということになる。

.cell {
  grid-row-start: -2;
  grid-column-start: -3;
  grid-row-end: -1;
  grid-column-end: -1;
}

命名した区切り線の指定

### 区切り線とその命名grid-template-rowsgrid-template-columnsを使って区切り線に名前を付けたが、この名前で範囲を指定することも出来る。

.cell {
  grid-row-start: row-b;
  grid-column-start: column-b;
  grid-row-end: row-c;
  grid-column-end: column-d;
}

命名した領域の指定

### セル領域の命名grid-template-areaを使ってセル領域に名前を付けたが、grid-areaプロパティにはこの名前を指定することも出来る。

.cell {
  grid-area: area-d;
}

区切り線からの長さ(スパン)で指定

セル領域は 区切り線から区切り線 による指定だけではなく、距離で指定可能である。昔のテーブルレイアウトのrowspancolspanと同じようなものと思って良い。

.cell {
  grid-row: 2 / 3;
  grid-column: 2 / span 2;
}

このようにspanキーワードを使って、セルの数を指定可能。もちろんショートハンドプロパティだけでなく、grid-row-endプロパティにspan 2と指定も出来るが、開始点と距離がペアになっている方が一見わかりやすそう。ケースバイケースだけど。

グリッド要素における子要素の整列

グリッド要素に対して、justify-contentないしalign-contentを使う。Flexboxと同じ要領。

親要素に対するセル要素自身の整列

セル要素に対して、justify-selfないしalign-selfを使う。こちらもFlexboxと同じ要領。

タイトルと URL をコピーしました