二次元的なレイアウトが可能になる次世代のCSSレイアウト、Grid Layout Moduleについて

こんにちは、制作部 松本です。

私はこれまでCSSレイアウトでdisplayプロパティ用いる際、inline-blocktable
最近ではflexboxを使用してきました。
今でもfloatを多用している方はあまりいないのではないかと思います。

本記事では、よりフレキシブルなレイアウトが実現できるgridについて紹介します。
gridは複雑なため、まだ体系的に全ての機能を説明できるほど私の理解も追いついていないので、今回はざっくりとした紹介となります。

対応ブラウザ

2017年4月現在、すでにほとんどのブラウザでgridが対応可能になっています。
残るはAndroid Browserのみ。
Can I Use CSS Grid Layout

gridで何ができるのか

一言で言えば、flexboxtable同様にマルチカラムレイアウトすることができるプロパティです。
flexboxが一次元的なレイアウトなのに対して、gridは二次元的なレイアウトが可能(らしい)です。

gridの概要

グリッドコンテナdisplay:grid;を指定された要素。
グリッドアイテムdisplay:grid;を指定された要素の直下の子要素。
孫要素はグリッドアイテムとみなされない。
グリッドトラックgridcolumn(列)row(行)の総称。
htmltableタグをイメージしてもらうとわかりやすいです。
グリッドライングリッドトラック間の線。
グリッドセルグリッドラインによって分けられた個々のスペース。
グリッドエリア複数のセルをまとめたグリッド内の特定の領域。

gridのプロパティ

グリッドコンテナのプロパティ
grid要素をグリッドコンテナとして定義する。
grid-template-columnsグリッドトラック(列)のサイズを指定する。
grid-template-rowsグリッドトラック(行)のサイズを指定する。
grid-template-areasグリッドエリアの名前を参照して、グリッドテンプレートを定義する。
grid-templategrid-template-columnsgrid-template-rowsgrid-template-areasを指定できるショートハンド。
grid-column-gapグリッドトラック(列)の間を指定する。
grid-row-gapグリッドトラック(行)の間を指定する。
grid-gapgrid-column-gapgrid-row-gapを指定できるショートハンド。
justify-itemsグリッドアイテムの行方向の整列。
align-itemsグリッドアイテムの列方向の整列。
justify-contentグリッドトラックの行方向の整列。
align-contentグリッドトラックの列方向の整列。
grid-auto-columns自動的に生成されたグリッドトラックのサイズを指定する。
grid-auto-rows自動的に生成されたグリッドトラックのサイズを指定する。
grid-auto-flow明示的に配置されていないグリッドアイテムの配置を指定する。
グリッドアイテムのプロパティ
grid-column-startグリッドアイテム(列)の開始位置を指定する。
grid-column-endグリッドアイテム(列)の終了位置を指定する。
grid-row-startグリッドアイテム(行)の開始位置を指定する。
grid-row-endグリッドアイテム(行)の終了位置を指定する。
grid-columngrid-column-startgrid-column-endを指定できるショートハンド。
grid-rowgrid-row-startgrid-row-endを指定できるショートハンド。
grid-areaグリッドセルに名前を付けてgrid-template-areasプロパティで参照できるようにする。
grid-columngrid-rowのショートハンドでもある。
justify-selfグリッドアイテム内のコンテンツを行方向に整列する。
align-selfグリッドアイテム内のコンテンツを列方向に整列する。

サンプル

上図のようなレイアウトを実現する場合、HTML/CSSの構造はとても単純です。

HTML

<div class="container">
    <div class="item item-a">A</div>
    <div class="item item-b">B</div>
    <div class="item item-c">C</div>
    <div class="item item-d">D</div>
    <div class="item item-e">E</div>
    <div class="item item-f">F</div>
</div>

CSS

.container {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 100px 100px;
    grid-gap: 10px;
    color: #444;
}

.item {
    background: #bbb;
    color: #fff;
    padding: 10px;
    font-size: 150%;
}

.item:nth-child(odd) {
    background: #333;
}

このコードを図解すると↓のようになります。

    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 100px 100px;

この記述は嚙み砕くと、
width100pxのグリッドアイテムを3列
height100pxのグリッドアイテムを2行
ということです。

ちなみにショートハンドで書くとこんな感じです。

    grid-template:100px 100px / 100px 100px 100px;

grid-template-columnsを以下のように変更します。

    grid-template-columns: 100px 100px 100px 100px;

するとwidth100pxのグリッドアイテムを4列になるので、Dのグリッドアイテムが1行目に移動します。

グリッドアイテムの数が多い場合、repeatを使うと便利です。

    grid-template: repeat(5, 100px) / repeat(5, 100px);

これは↓と同じ意味です。

    grid-template-columns: 100px 100px 100px 100px 100px;
    grid-template-rows: 100px 100px 100px 100px 100px;

Aのグリッドアイテムだけ、横幅を広げたい場合、

.item-a {
    grid-column:span 4;
}

これはtableタグのcolspan="4"と同様の動きをします。
このとき、Fのグリッドアイテムのheightが100px以下になっていますが、
それはgrid-template-rows: 100px 100px;の記述で、2行目までしかheightを指定していないためです。

次に、gridでもっとも重要と思われるgrid-areaについて説明します。
この機能を使うためには、まずテンプレートに定義したい要素に名前をつけます。

.item-a {
    grid-area: area-a; /* .item-aにarea-aという名前をつける */
}

.item-b {
    grid-area: area-b;
}

.item-c {
    grid-area: area-c;
}

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

.item-e {
    grid-area: area-e;
}

.item-f {
    grid-area: area-f;
}

グリッドコンテナにテンプレートを定義します。

.container {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 100px 100px;
    grid-template-areas:"area-a area-b area-c"
                        "area-d area-e area-f";
    grid-gap: 10px;
    color: #444;
}

grid-template-areasの値はそのままグリッドアイテムの並びと連動します。

・グリッドアイテムの順番を変える場合

    grid-template-areas:"area-e area-c area-b"
                        "area-f area-a area-d";

・グリッドアイテムの要素を広げる場合

    grid-template-areas:"area-e area-c area-c"
                        "area-e area-a area-f"
                        "area-b area-d area-d";

・グリッドエリア内に空白部分が欲しい場合

    grid-template-areas:"area-e area-c ......"
                        "area-e area-a area-f"
                        "area-b area-d area-d";

視認性を考え他のエリア名と文字数を揃えていますが、「.」はひとつでも構いません。

・複雑なレイアウトの場合

    grid-template-areas:"area-a ...... ...... area-c"
                        "...... area-e area-f area-c"
                        "area-b area-b area-f area-c"
                        "...... area-d ...... area-c";

こんな面倒くさそうなレイアウトもとても簡単です!

grid特有の単位

グリッドアイテムのサイズにはpxemrem以外にfr(flex fraction)が指定できます。

    grid-template-columns: 200px 2fr 1fr;
    grid-template-rows: 200px 200px;

frは、グリッドアイテムの配置可能な領域を占める割合を表します。
flexboxflex-growと同様の動きをすると考えるとわかりやすいです。

2fr1frの2倍の幅になります。

まとめ

ざっくりとした紹介にはなりましたが、いかがでしたでしょうか?
恐らくgridの機能の10分の1程度しか紹介できていませんが、もっと色々な機能を使いこなせるようになれば最強の武器になると思います。

Androidでも対応可能になるその日までに、少しでも理解を進めておいて損はないのではないでしょうか!