Hiratake Web ロゴ

CSS Grid の subgrid でフォームをいい感じにする

投稿した日
更新した日
書いたひと
icon
ひらたけ

ウェブサイトには、よくお問い合わせ用などのフォームが設置されています。テキストを入力する場所があって、その上や隣に「お名前」「住所」など何を入力するかを説明するラベルが配置されているようなものが一般的ではないかなと思います。

今回は、以下の画像のようなフォームを、いつの間にか PC の主要なブラウザでサポートされていた CSS Grid の subgrid を使用していい感じにマークアップします。

よくある感じのフォームの画像

仕様

作成するフォームの仕様は以下のとおりです。

  • PC(幅の広い画面)で表示する場合には 入力欄とそのラベルを横並びに表示 、SP(スマートフォンなど幅の狭い画面)で表示する場合には ラベルを入力欄の上に表示 する。
  • 入力欄とラベルを横並びにする際、 入力欄とラベルはそれぞれ左端の位置が揃うようにする

実際のフォームでは余白の大きさなども指定があると思いますが、その辺りはなんとなくで。エラーメッセージを出す場合の表示とか必須マークを入れるとか色々あると思いますが、今回は考慮しないものとします。

また、今回作成するフォームでは Tailwind CSS を使用します。

つくったもの

コードだけ見たいという方のために、作成したものを以下に置いております。

サブグリッドを使う

詳しい説明は以下の MDN に画像やサンプルコード付きであるので見ていただければと思いますが、 display: grid を追加した グリッドコンテナを入れ子にした場合に子のグリッドを親のものと同じサイズにできる というものです。

今回作成するフォームをマークアップするとき、PC での表示を実現しようとすると「入力欄とラベルはそれぞれ左端の位置が揃うように」するために以下のような手法を用いることになると思います。

  • display: table もしくは table タグを使う。
  • フォーム全体を 2 列のグリッドコンテナにする。

display: tabletable タグを使う方法は、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: tabletable タグでどうにかしていた箇所を置き換えられそうなので、かなり使い所がありそうな感じがします。まだ全ブラウザが対応しているというわけではなさそうですが、MDN のブログ のコードなどを覗くと普通に使われてるので、普通に使ってもいいのかも?とか思うなどします。