カードの高さを揃えたければsubgridを使えばいい

カテゴリ:
CSS
投稿日:

広告

従来の方法では一箇所しかコンテンツの高さを揃えることができない

カードの高さを揃える際のアプローチとしてはdisplay:flex; flex-direction:column;もしくはdisplay:grid;を使用した方法が主流かと思われます。

/* カードを横並びする要素 */
.card-wrapper {
display: block grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
/* flexを使用した方法 */
.card {
display: block flex;
flex-direction: column;
}
.card-title {
flex: 1;
}
/* gridを使用した方法 */
.card {
display: block grid;
grid-template-rows: auto auto 1fr auto; /* titleの行を1frと指定 */
}
  • display:flexを使用した例では揃えたい要素(ここではタイトルとします)にflex:1を適用して、その部分が可変のスペースを吸収するように設定しています。
  • display:gridを使用した例ではgrid-template-rowsを使い、タイトル部分を1frとすることでそのコンテンツが残りの空間を埋めるように設定しています。

この方法であれば一箇所のコンテンツの高さを揃えつつ並べることができますが、複数箇所の高さを揃えることができません。また、flex:1もしくはgrid-template-rows1frを指定した部分以外が不均一になると、全体の高さが一致しなくなるリスクがあります。

全体の高さが一致しなくなってしまったカードの表示例

従来の方法で複数箇所の高さを揃えるにはセマンティックではないtable要素を使用するか、JSで高さを調整するしかアプローチがありませんでした。現在ではsubgridを使用すれば適切なマークアップを保ちつつ、CSSのみで解決することができます。

※ matchHeight.jsを使用した高さを揃える方法を紹介している文献がありますが、これはfloat:leftで並べていた頃の遺物なので現在は使用する必要はありません。

subgridを使えば全てのコンテンツの高さを揃えることができる

subgridを使う方法は至極簡単で、先程紹介したdisplay:gridを用いたアプローチのgrid-template-rowsの値をsubgridに変更し、grid-rowプロパティにspan {コンテンツの数}を指定したものを追加するだけです。

/* これを */
.card {
display: block grid;
grid-template-rows: auto auto 1fr auto;
}
/* こうする */
.card {
display: block grid;
grid-template-rows: subgrid;
grid-row: span 4;
}

See the Pen by tak-dcxi (@tak-dcxi) on CodePen.

今回のサンプルではサムネイル、タイトル、紹介文、価格の4行分のトラックを使用しているため、grid-rowプロパティの値はspan 4となります。subgridでは暗黙的なgridは生成されないため、コンテンツの数に対応したgrid-rowの指定がないと崩れて表示されてしまいます。指定漏れがないように気をつけてください。

また、サンプルでは全てのコンテンツの高さが揃っていることを証明するためにカードの横幅を固定値にしておりますが、仮に行を折り返したとしてもカード内の要素の高さ揃えは綺麗なまま維持されます。JSで高さを調整する場合、行の折り返しが発生する際の細かな調整が必要でしたがsubgridでは不要です。

行を折り返したとしても親グリッドのトラックにより高さ揃えが綺麗なまま維持される

直接の子要素でないとsubgridは適用できないので注意

subgridを指定する際は「display:gridで並べる要素>subgridを指定する要素>各コンテンツ」の構造でなければ適用できません。

以下の構造では「カードを並べる要素>section要素>a要素>各コンテンツ」となっており、そのままでは余分な要素が介入しているためsubgridが適用できなくなっています。

<div class="card-wrapper">
<section>
<a href="...">
<h2>タイトル</h2>
<div>サムネイル</div>
<p>紹介文</p>
<p>価格</p>
</a>
</section>
...
</div>

この例であればsection要素にdisplay:contentsを指定し、a要素にsubgridを指定することで解決できます。

section {
display: contents;
}
a {
display: block grid;
grid-template-rows: subgrid;
grid-row: span 4;
}

ただし、display:contentsはスクリーンリーダーで読み上げが行われない可能性があるなどアクセシビリティに不都合が生じる可能性があります。 div要素やaccessible nameの無いsection要素であれば問題はないかと思われますが、スクリーンリーダーでの確認は怠らないようにしてください。

subgridは全てのモダンブラウザでサポート済み

subgridは全モダンブラウザで対応されております。iOS Safariはバージョン16からの導入なので、それ以前のバージョンをサポートする場合は残念ながら使用を控える必要があります。


当ブログの記事一覧にもsubgridが使用されています。

本文上部へ戻る

折りたたみメニュー