CSSサブグリッドで真のフレキシブルなレイアウトを実現する方法

2019年12月3日、Firefox71がリリースされ、このバージョンから **CSS Subgrid** が使用できるようになりました。
CSS Subgridは2016年来からW3CのWorking Draftによって勧告されていましたが、今回のFirefoxのアップデートによって遂にユーザーへ提供できるようになりました。
この記事では、CSS Subgridの何が我々をワクワクさせ、どのようにインタフェースの実装を変化させてくれるのかについて紹介したいと思います。

## CSS Subgrid とは
### CSS Gridのおさらい
CSS Subgridの説明の前に、簡単にCSS Gridのおさらいをします。
CSS Gridとは、2次元レイアウトをCSSを用いて簡潔に組むための仕組みを指します。
任意の要素に`display: grid;`を適用することで、以下の画像のように対象の要素は**グリッドコンテナー**として、グリッドコンテナーの子要素は**グリッドアイテム**として扱われます。
![Group.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48027/2dc8e38c-f6a0-54eb-6b40-b8351be77661.png)

```html
<ul style="display: grid;"> <!-- グリッドコンテナー -->
  <li>ぺんぎん</li> <!-- グリッドアイテム -->
  <li>あざらし</li> <!-- グリッドアイテム -->
  <li>らっこ</li> <!-- グリッドアイテム -->
</ul>
```

### CSS Gridの問題点
CSS Gridを用いることで、グリッドアイテムの高さを柔軟に揃えることが可能となりました。
では、我々の戦いはGridの登場によって終わりを迎えたのでしょうか。

そんなことはありません。グリッドアイテムの中の要素に目を向けるとどうでしょう。
グリッドアイテムの中には画像やテキスト等の複数の要素を設ける必要があります。これらのテキストはコンテンツによって変化するため、実装時には様々な高さへ変化することを想定しなくてはいけません。

しかしながら、グリッドアイテムは以下の画像のように、中の要素の高さまでは揃えることができません。
![Group 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48027/7b6ec017-8cdc-34ec-8c59-89fd4d6ba16a.png)


### CSS Subgridの登場
この問題を解決してくれるのがCSS Subgridです。
詳細な実装方法は後述しますが、グリッドアイテム要素に対して`grid-template-columns: subgrid;`や`grid-template-rows: subgrid;`を指定することで、CSS Subgridを有効化させることができます。
有効化させることで、グリッドアイテムの中の要素をサブグリッドアイテムとして扱うことができ、アイテム毎に高さを可変させることが可能となります。

以下の例ではSubgridを用いてタイトル部分の高さを可変させています。Subgrid未適用時は高さがコンテンツ毎に異なっているのに対し、Subgrid適応時は高さが統一されてるかと思います。

| 未適用時 | 適用時 (Firefox 71) |
|:---|:---|
| <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48027/28e764e3-8bb1-c387-4dfd-70ef716990ef.png" width="100%" alt=""> | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48027/f4d6441e-aa26-acd3-4046-f25f7f903ccb.png" width="100%" alt=""> |

Subgridを自在に操ることで、真のフレキシブルなレイアウトを簡潔に実現することが可能となります。

### 対応環境 (2019/12/07現在)
現在はFifefox 71~ のみ対応しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48027/8c1c8c80-cf48-0a66-900c-9473d32349b3.png)
[Subgrid | Can I Use...](https://caniuse.com/#feat=css-subgrid)より

## 使い方
### サンプル
<p class="codepen" data-height="480" data-theme-id="light" data-default-tab="result" data-user="oreo" data-slug-hash="JjoGjKo" style="height: 480px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Sample of CSS Subgrid">
  <span>See the Pen <a href="https://codepen.io/oreo/pen/JjoGjKo">
  Sample of CSS Subgrid</a> by oreo (<a href="https://codepen.io/oreo">@oreo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
（Firefox 71~で確認してみてください。）


### 実装方法
Subgridは以下のソースコードで対応することが可能です。

```html
<ul class="gridContaienr">
  <li class="gridItem">
    <img src="https://via.placeholder.com/150" alt="">
    <h3>タイトル</h3>
    <p>テキスト</p>
    <a href="http://example.com/">リンク</a>
  </li>
  <li class="gridItem">
    <img src="https://via.placeholder.com/150" alt="">
    <h3>タイトル</h3>
    <p>テキスト</p>
    <a href="http://example.com/">リンク</a>
  </li>
  <li class="gridItem">
    <img src="https://via.placeholder.com/150" alt="">
    <h3>タイトル</h3>
    <p>テキスト</p>
    <a href="http://example.com/">リンク</a>
  </li>
</ul>
```

```css
.gridContainer {
  display: grid;
  grid-template-columns: repeat(3, minmax(200px, 1fr));
  grid-gap: 1em;
}

/* 以下の記述を追加 */
.gridContainer .gridItem {
  display: grid;
  grid-row: span 4;
  grid-template-rows: auto auto 1fr auto; /* fallback for non-supported browsers */
  grid-template-rows: subgrid;
}
```

まずは`.gridItem`へ`display: grid;`を指定することでグリッドコンテナーとして扱う必要があります。
同時に、`grid-template-rows: subgrid;`を指定することで、グリッドコンテナーをサブグリッド化することができます。

こちらの例ではSubgridに対応していないブラウザ用のフォールバックとして、`grid-template-rows: auto auto 1fr auto;`を指定しています。
可変させる要素と固定させる要素を明示することで、Subgridに対応していないブラウザでも最低限のレイアウトを担保できるので、未サポートブラウザが多い現在はこちらの記述も必須でしょう。

## 終わりに
CSS SubgridはFlexやGridだけでは実現できなかったレイアウトを簡潔に実現できる力を秘めていると考えられます。
現在はFirefoxのみが対応していますが、今後より多くのメジャーなブラウザへの実装され、ユーザーへ提供できるようになることを願ってやみません。


## 参考サイト
- [Subgrid - CSS | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Grid_Layout/Subgrid)
- [Grid - CSS | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout)
- [Subgrid | Can I Use...](https://caniuse.com/#feat=css-subgrid)
- [Firefox 71: A year-end arrival | Mozilla Hacks the Web developer blog](https://hacks.mozilla.org/2019/12/firefox-71-a-year-end-arrival/)