CSS Grid の subgrid でフォームをいい感じにする
- 投稿した日
- 更新した日
- 書いたひと
- ひらたけ
ウェブサイトには、よくお問い合わせ用などのフォームが設置されています。テキストを入力する場所があって、その上や隣に「お名前」「住所」など何を入力するかを説明するラベルが配置されているようなものが一般的ではないかなと思います。
今回は、以下の画像のようなフォームを、いつの間にか PC の主要なブラウザでサポートされていた CSS Grid の subgrid
を使用していい感じにマークアップします。
仕様
作成するフォームの仕様は以下のとおりです。
- PC(幅の広い画面)で表示する場合には 入力欄とそのラベルを横並びに表示 、SP(スマートフォンなど幅の狭い画面)で表示する場合には ラベルを入力欄の上に表示 する。
- 入力欄とラベルを横並びにする際、 入力欄とラベルはそれぞれ左端の位置が揃うようにする 。
実際のフォームでは余白の大きさなども指定があると思いますが、その辺りはなんとなくで。エラーメッセージを出す場合の表示とか必須マークを入れるとか色々あると思いますが、今回は考慮しないものとします。
また、今回作成するフォームでは Tailwind CSS を使用します。
つくったもの
コードだけ見たいという方のために、作成したものを以下に置いております。
サブグリッドを使う
詳しい説明は以下の MDN に画像やサンプルコード付きであるので見ていただければと思いますが、 display: grid
を追加した グリッドコンテナを入れ子にした場合に子のグリッドを親のものと同じサイズにできる というものです。
今回作成するフォームをマークアップするとき、PC での表示を実現しようとすると「入力欄とラベルはそれぞれ左端の位置が揃うように」するために以下のような手法を用いることになると思います。
display: table
もしくはtable
タグを使う。- フォーム全体を 2 列のグリッドコンテナにする。
display: table
や table
タグを使う方法は、PC 表示のときは良いですが SP 表示の場合にラベルと入力欄を上下に配置したり、項目同士の間隔を空けたりするのが大変そうです。
フォーム全体をグリッドコンテナにする場合は、 grid-template-columns: auto 1fr
みたいな指定をして、そのコンテナの直下にラベルと入力欄のタグを入れることになります。
<form>
<dl class="grid grid-cols-[auto_1fr]">
<dt>お名前</dt>
<dd>
<input name="name" type="text" />
</dd>
<dt>ニックネーム</dt>
<dd>
<input name="nickname" type="text" />
</dd>
</dl>
</form>
たしかに左端は揃えられますが、こちらも 1 つ目の方法と同様に SP 表示の際の項目同士の間隔を空けたりするのが大変そうです。グリッドコンテナの直下にラベルと入力欄が同列で入っているので、全てを縦方向に積んだときに、 項目間の余白は大きめ で ラベルと入力欄の間の余白は小さめ というのが一括で指定できません。
ラベルに上方向の margin
を入れるとかすれば調整できないこともないとは思いますが、せっかく Grid を使っているので gap
でどうにかしたいところです。
そこで、CSS Grid の Subgrid を使用します。dl
要素の中には dt
dd
の他に、グルーピング目的での div
タグが許可されているので、項目ごとに div
タグで囲み、その div
タグがグリッドコンテナの 2 列分の幅を使うようにします。そして、親のグリッドと列の大きさが同じになるよう grid-template-columns: subgrid
を指定します。
<form>
<dl class="grid grid-cols-[auto_1fr] gap-8">
<div class="col-span-full grid grid-cols-[subgrid]">
<dt>お名前</dt>
<dd>
<input name="name" type="text" />
</dd>
</div>
<div class="col-span-full grid grid-cols-[subgrid]">
<dt>ニックネーム</dt>
<dd>
<input name="nickname" type="text" />
</dd>
</div>
</dl>
</form>
親のグリッドコンテナ(dl
)で gap: 32px
を指定しているため項目間の余白は 32px となっていますが、サブグリッドでは親のグリッドコンテナの gap
も継承するので、ラベルと入力欄の間も同じ 32px となります。
PC 表示のほうができたので、SP 表示のほうを対応します。項目間の余白はそのままで良いですが、ラベルと入力欄を縦並びにして余白を小さくする必要があります。SP 表示の場合は親のグリッドと列を合わせる必要がないので、サブグリッドが PC 表示の場合にだけ適用されるように変更します。
また、子のグリッドコンテナの縦方向の gap
を別途指定してあげます。
<form>
<dl class="grid grid-cols-[auto_1fr] gap-8">
<div class="col-span-full grid gap-y-2 md:grid-cols-[subgrid]">
<dt>お名前</dt>
<dd>
<input name="name" type="text" />
</dd>
</div>
<div class="col-span-full grid gap-y-2 md:grid-cols-[subgrid]">
<dt>ニックネーム</dt>
<dd>
<input name="nickname" type="text" />
</dd>
</div>
</dl>
</form>
これで仕様に沿ったフォームができました!あとは見た目を整えてあげれば完成です。
サブグリッドは display: table
や table
タグでどうにかしていた箇所を置き換えられそうなので、かなり使い所がありそうな感じがします。まだ全ブラウザが対応しているというわけではなさそうですが、MDN のブログ のコードなどを覗くと普通に使われてるので、普通に使ってもいいのかも?とか思うなどします。