subgrid指定時に子要素の高さが変化する現象を検証
CSSのsubgridは行(列)のスタート位置を合わせるのに大変便利で、全ての主要ブラウザでサポートされてから実務で使用することが増えてきたように感じます。
ただグリッドコンテナーにgap
を指定した際に、subgridの子要素(グリッドコンテナーからみた孫要素)のサイズが変化することがあり注意が必要です。この記事はその現象について検証しています。
どのような現象か
まずはsubgridを用いたレイアウトのおさらいです。
以下は一般的なカードレイアウトです。subgridを使用することで各行のスタート位置を揃えています。(この後の説明をわかりやすくするため各行間の余白は無しにしています)
上記では右側のカードのみ見出しの文字数が多いですが、その下の抜粋とボタンの行頭がそろっています。
JavaScriptを書くことなくCSSだけでとても綺麗なレイアウトを表現できるので本当にありがたいプロパティです。
大変便利なsubgridですが、親要素に大きめのrow-gapを指定するとレイアウトが変化することがあります。以下は先ほどの例のグリッドコンテナーにrow-gap: 100px;
を指定しました。
見出しと抜粋の下側に余白が生まれてしまいました。
subgridはグリッドコンテナーのgap
を継承するためそれが原因ではと思うかもしれませんが、subgridを指定している要素ではrow-gap
を0で上書きしています。
これが今回遭遇し検証した現象です。
上記ではsubgridの子要素間の余白が変化したように見えますが実際にはsubgridの子要素の高さが変化しています。わかりやすくするために、subgridの各子要素に背景色をつけてみました。
- サムネイル:赤
- 見出し:青
- 抜粋:緑
- ボタン:紫
見出しと抜粋の高さが変化していることがわかります。ボタンの高さもわずかに変化しています。
どのような場合に発生するのか
検証した結果以下の条件でsubgridの子要素の高さが変化するようです。
子要素の種類 | 子要素の高さが変化する条件 |
---|---|
startまたはendの要素 | グリッドコンテナーのrow-gap の値 > その要素の高さの2倍 |
startまたはend以外の要素 | グリッドコンテナーのrow-gap の値 > その要素の高さ |
startの要素とは一番上の要素で、上の例ではサムネイルが該当します。endの要素とは一番下の要素で、上の例ではボタンが該当します。
上の例に具体的に当てはめると以下のようになります。
子要素の種類 | 要素の高さ | 高さが変化するrow-gap の値 |
---|---|---|
サムネイル(start) | 150px | 301px |
タイトル | 62px | 63px |
抜粋 | 26px | 27px |
ボタン(end) | 48px | 97px |
今回の例ではsubgridの子要素の内、最小の高さを持つのは抜粋の26pxです。グリッドコンテナーのrow-gapが27pxよりも大きくなると本来想定していたレイアウトとは異なるものとなってしまいます。
なぜこのような現象が起きるのか
サブグリッドにgap: 0;
を設定した場合、その子要素にマイナスマージンを適用するのと同じように動作するためです。 MDNのサブグリッドのページでも以下のように記載されています。
(中略)so when we set the gap to 0, it acts in a similar way to applying a negative margin to an element, giving the space from the gap back to the item.
つまりサブグリッドにgap: 0;
を設定した場合、余白の調整はgap
からsubgridの子要素そのものへと移動し、subgridの子要素のマージンで調整しているということになります。
次の画像はサブグリッドのgapを0のまま、グリッドコンテナーのgapを25pxに変更した時の開発者ツールの表示です。
矢印で示している罫線のラインがグリッドコンテナーの余白です。この余白が表示されないようにsubgridの子要素がマイナスマージンで見えない調整をしています。
そこにグリッドコンテナー側で大きな余白を設定すると、subgridの子要素のマイナスマージンもつられて大きくなり、結果として子要素の高さが変化するようです。
不思議な挙動ではありますがこの現象はバグではなく想定されたプロパティの動きのようです。
とはいえグリッドコンテナーに大きめのgap(今回ではrow-gap: 100px;
)を指定する機会は多いかと思うので、場合によってはsubgridが使いにくいケースがあるかもしれません。そのような場合には以下の選択肢を検討する必要がありそうです。
- JavaScriptを使用して行頭をそろえる
- グリッドアイテムの
grid-templete-row
を固定値にして行頭をそろえる(表示する行の調整が必要) - 行頭そろえを断念する
なお今回はgridを使用した縦型のレイアウトにおける高さの変化を検証しました。横型レイアウトでの幅の変化については検証しておりません(おそらく同様の挙動だと推測されます)。