TL;DR
複数の dl 要素による name-value リストにおいて、name 列(dt 要素)の幅を CSS だけで動的に(幅を決め打ちしないで)揃える方法です。
グリッドレイアウト display: grid
と display: contents
で実現できます。ただし、2018 年 9 月時点で IE 11 と Edge は後者をサポートしていません。
お急ぎの方は CodePen をご覧ください。
背景
Web アプリの UI を実装していると、よく次のような name-value リストが必要になることがあります。
このようなリストは HTML では通常 dl, dt, dd 要素を用いて次のようなマークアップを行います。
<div class="container">
<header>
<h1>User Information</h1>
</header>
<div class="content">
<dl>
<dt>Username</dt><dd>john-smith</dd>
</dl>
<dl>
<dt>Full name</dt><dd>John Smith</dd>
<dt>Age</dt><dd>20</dd>
<dt>Email address</dt><dd>john-smith@example.com</dd>
</dl>
<dl>
<dt>Type</dt><dd>Admin</dd>
<dt>Language</dt><dd>English</dd>
</dl>
</div>
</div>
ここで、上図の破線のように、name 列(dt 要素)の幅を揃えたいとします。全ての行が一つの dl 要素内であれば、display: table
などを用いて比較的簡単に実装できます。
しかし、今回は複数の dl 要素からなっています。こういった場合にリストをまたいで name 列の幅を揃えるにはどうすればよいでしょうか。この記事では、その具体的な方法を書きます。
なお、複数の dl 要素を使っているのは、リストを意味ごとにグループ分けしたいという目的があるので、スタイルのためにマークアップを変更するのは前提として避けます。
グリッドレイアウト + display: contents
方法としては、グリッドレイアウト display: grid
と display: contents
を用います。スタイルシートは次のような感じになります(重要な部分のみ抜粋)。
.content {
display: grid;
grid-template-columns: max-content 1fr;
}
dl {
display: contents;
}
リストのコンテナでグリッドを定義
まず、複数の dl 要素を持つコンテナ(今回は <div class="content">
...</div>
)で display: grid
とし、grid-template-columns
で列の幅を定義します。
ポイントは一列目の max-content
で、これは要素の中身に合わせて幅が最適化されるという非常に便利な値です。今回のケースでは、dt 要素の中のテキストが改行されないように、かつ余りが出ないようにピッタリな幅を自動的に計算してくれます。
max-content
は CSS Intrinsic & Extrinsic Sizing Module Level 3 で追加されました。より詳細を知りたい方は Intrinsic Size Determination セクションをご覧ください。
これで、以下のようなグリッドレイアウトで表示されるようになります。
でも崩れてしまっていますね…。それもそのはず、定義した各グリッドの中に入るのは、display: grid
にした要素の直下の要素だからです(「グリッドアイテム」と呼ばれます)。直下にあるのは dl 要素なので、リストごと各グリッドの中に放り込まれている状態です。
display: contents
でその要素を “無かったことに” する
そこで登場するのが、display: contents
です。これは、指定した要素を “無かったことに” します。これを先ほどの dl 要素に対して指定することで、dl 要素は無かったこととしてレイアウトされ、その中の dt, dd 要素が display: grid
にした要素の直下に来るようになります。
よって、以下のようなレイアウトになり、作りたかったものができました。
display: contents
のイメージとしては、それを指定した要素だけが display: none
になることかなと思います。display: none
はその要素自身とその配下の要素すべてが生成されなくなりますが、display: contents
は自身だけが生成されず、その配下の要素は通常通り生成されます。
display: contents
は CSS Display Module Level 3 で定義されています。詳細は Box Generation: the ‘none’ and ‘contents’ keywords セクションをご覧ください。
また、display: contents
の用途などについてはこちらの記事 “More accessible markup with display: contents” がわかりやすいです。
対応ブラウザ
2018 年 9 月時点での各機能の実装状況です。IE 11 と Edge は対応していないのでご注意ください。
max-content
display: contents
ソースコード・デモ
CodePen でご覧いただけます。