Firefox や Safari ではすでにサポートされている CSS Subgrid(サブグリッド)ですが、Google Chrome でも 2023 年 9 月上旬リリース予定の 117 よりサポートされます12。
Microsoft Edge でのサポートは今のところ未定ですが、Chrome に追従すると考えれば、バージョン 117 がリリースされる 2023 年 9 月中旬以降になるでしょう3。
この記事では、まもなく主要なブラウザでサポートされる CSS Subgrid について、実例を取り上げながら特徴や使い方を説明します。
CSS Subgrid の基本
見出し「CSS Subgrid の基本」サブグリッドは W3C の仕様では「CSS Grid Layout Module Level 2」に属しており、基本的な特徴としては以下が挙げられます。
- 子要素の配置を親グリッドのトラックに紐づけることができる
- サブグリッドを指定した子要素から、さらに直下の子要素にも指定できる
- 行、列のどちらか一方、もしくは両方を指定できる(
grid-template-rows
とgrid-template-columns
) - 親グリッドで指定した余白(
gap
)は上書きできる
以下にコードを抜粋します。
CSS Subgrid の注意点
見出し「CSS Subgrid の注意点」実例のなかでも一部言及しますが、サブグリッドの注意点としては以下が考えられます。
- サブグリッドのライン番号はリセットされ、再び
1
から開始する - 暗黙のグリッドは生成されない
- 親グリッドと結びつくため、HTML 構造に対する依存度は高くなる
- 一足飛びに先祖要素のサブグリッドを定義することはできない
これらを踏まえたうえで、サブグリッドの実例を見ていきましょう。
例1: カードコンポーネント
見出し「例1: カードコンポーネント」まず、サブグリッドの使用例として一般的な、カードコンポーネントの例を挙げます。
このように、カードごとにコンテンツの量が異なるときに、適切なマークアップを維持したまま、隣り合う複数の要素の高さをそろえるには、従来であれば <table>
要素を使用するか、JS で高さを調整するしか方法がありませんでした。
しかし、JS を使用する方法では以下のような問題点や複雑性があります。
- 高さを算出するために、実行するにはレンダリングを待つ必要がある
- レンダリング後に実行されるため、レイアウトシフトが発生する(CLS への影響)
- JS の読み込みと実行により、パフォーマンス面に影響を及ぼす
- リフローに対応する必要がある(リサイズや文字サイズの変更など)
- レイアウトによって無効にする必要がある(モバイルでは無効など)
サブグリッドによって、JS を使用せずに高さ揃えが実現できます。以下はライブデモです。
CSS Subgrid に対応している環境でご確認ください。
このように、たとえ行を折り返したとしても親グリッドのトラックにより、コンポーネント内の要素の高さ揃えは維持されたままになります。ちなみに、4 番目のカードコンポーネントは、あえて見出し下のテキストが抜けた状態にしています。
関連するコードを抜粋します。
カードコンポーネントである .card-item
に対して、grid-template-rows: subgrid
を指定することで、親グリッドの行方向のトラックをサブグリッドとして使用できます。
続く grid-row: span 4
で、4 行分のトラックを使用することを明示しています。加えて、grid-row-gap: 16px
で、親グリッドで指定している gap: 40px
を上書きしています。
暗黙的なグリッドは生成されない
見出し「暗黙的なグリッドは生成されない」ここで注意する点としては、通常のグリッドレイアウトとは異なり、サブグリッドのトラックは暗黙的に生成されないということです。
さきほどの例では、grid-row: span 4
で、4 行分のトラックを明示しましたが、この指定がなかったり、要素数に対して指定するトラック数が不足していると、以下のように要素が重なってしまうため注意が必要です。
HTML 構造の制約
見出し「HTML 構造の制約」さらに注意する点としては、直接の子要素でないとサブグリッドとして定義できないので、カード全体を囲う要素と、カードコンポーネント自体の間に要素が入るとサブグリッドは適用されません。
例えば、以下のように「1. 親要素 > 2. 子要素 > 3. 孫要素」の構造で、「3. 孫要素」を「1. 親要素」のサブグリッドとして定義することはできません。
レイアウトによっては、「2. 子要素」をあわせてサブグリッドに定義することで解消できますが、カードコンポーネントの例では行トラックの生成がうまくいきません。
この例でも対応するには、「2. 子要素」に display: contents
を指定するのが近道ですが、この方法にも気をつける点があるので、それらを踏まえたうえで検討する必要があります。
なお、後述するポジショニングマップの例では、中間要素をサブグリッドとして定義して対応しています。
display: contents
見出し「display: contents」中間の要素に display: contents
を指定すると、グリッドアイテムとして認識されなくなるので、HTML の構造を維持したまま、その下の要素(孫要素)をサブグリッドとして定義することができます。
.parent {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.child {
display: contents;
}
.grandchild {
display: grid;
grid-template-rows: subgrid;
grid-row: span 4;
}
しかし、display: contents
を指定した要素にはボックスが生成されないため、余白や背景を指定できないので、活用できる場面は限定されます。
また、display: contents
には、アクセシビリティに関するブラウザ上のバグが存在しており、その多くは修正されましたが、いくつかのバグは残ったままです。
- It's Mid-2022 and Browsers (Mostly Safari) Still Break Accessibility via Display Properties | Adrian Roselli(外部リンクを開く)
- More accessible markup with display: contents | hidde.blog(外部リンクを開く)
カードコンポーネントの例のように、<div>
に指定する分には問題なさそうですが、念のため留意しておいたほうがよいでしょう。
例2: リストの行頭揃え
見出し「例2: リストの行頭揃え」次に、リストの行頭揃えの例を見ていきます。さきほどのカードコンポーネントでは行トラックをそろえましたが、今度は列トラックをそろえます。
以下はライブデモです。
この例では .list-item
に対して、grid-template-columns: subgrid
を指定し、列方向のグリッドトラックをサブグリッドとして使用しています。
行頭の番号は CSS の ::before
擬似要素に counter()
関数を使用して生成しており、意図的に桁数を変えていますが、この桁数の変化によって幅が異なる場合でもサブグリッドによってラインをそろえることができます。
このように、サブグリッドで列トラックをそろえる応用例として、以下のようなニュース一覧のレイアウトも考えられそうです。
例3: ポジショニングマップ
見出し「例3: ポジショニングマップ」最後に、行、列の両軸をサブグリッドに定義する例として、ポジショニングマップを実装します。
以下はライブデモです。
この例では、親グリッドとグリッドに配置したいアイテムとの間に中間要素が存在します。
以下は抜粋したコードですが、子要素(.map-list
)と孫要素(.map-item
)に対して、grid: subgrid / subgrid
を指定し、行・列ともにサブグリッドを定義しています。
ちなみに、正方形の可変グリッドを生成するために、grid: repeat(10, 10cqi) / repeat(10, 10cqi)
の指定で、コンテナクエリの単位(cqi
)を使用しています。
おわりに
見出し「おわりに」この記事では、実例を挙げながら CSS Subgrid の基本的な使い方を説明しました。
サブグリッドについては、なんとなく概念を理解しているつもりでしたが、実際にコードを書いてみるとうまくいかない場面があり、やはり手を動かすことは重要だと改めて実感しました。
今後、使っていくうちに、より有用な使い方や新たな課題が見つかるかもしれませんので、引き続き実践をとおして、サブグリッドの使い方を考えていきます。
参考文献
見出し「参考文献」本記事の作成にあたり、以下のウェブページを参考にしました。
- Subgrid | MDN(外部リンクを開く)
- CSS Grid Layout Module Level 2 | W3C(外部リンクを開く)
- CSS Subgrid | 12 Days of Web(外部リンクを開く)
- Learn CSS Subgrid | Ahmad Shadeed(外部リンクを開く)