🐈‍⬛

subgrid を駆使した入力フォーム実装レシピ 〜ラベル天地中央揃えを添えて〜

に公開1

この記事でわかること

このようなレイアウトの入力フォームの実装方法をご紹介します。

構成はざっくりと以下のようになっています。

構成

このレイアウトの特徴は、

  • ラベルの位置が入力フィールドに対して天地中央
  • input にはバリデーションがあり、未入力時には入力フィールドにテキストが表示される

です。
ここからは実装の詳細を記載していきたいと思います。

地味に難しいこと

前章で述べた「ラベルの位置が入力フィールドに対して天地中央」に尽きます。
このように単にラベルが上部につくだけであれば、様々なやり方で秒で実現が可能でしょう。

ラベルが各フィールドの上部につく

しかし、ラベルの位置が入力フィールドの高さに依存するとなると、入力フィールドとラベルの高さを一致させる必要があります。
特に input 下にはバリデーションテキストが表示されるという仕様があるので、入力フィールドの高さは状態によって可変になるのです。

subgrid とは?

記事タイトルでネタバレしていますが、実装には subgrid を用います。
実装方法の解説に入る前に、 subgrid について軽く触れておきます。既に知識がある方は読み飛ばしてください。

まず Grid Layout について説明します。これは、親要素に display: grid; を指定して、行と列を定義し、子要素をその格子の中に配置していくレイアウトシステムのことです。

では、 subgrid とは何者なのか?というと、これは「子グリッド」を意味します。
親要素を Grid にしても、子要素のサイズや位置は、あくまで親の定義したセルの範囲内で決まります。子要素をまた Grid にしても、親の作った格子の定義は引き継ぎません。

ここで登場するのが subgrid です。
subgrid を指定した子要素は、「親が持っている Grid の線の定義」をそのまま借りて、自分の Grid の線として使えます。

subgrid

こうすることで、親のレイアウト構造を、ネストされた深い階層までまるっと共有できます。これが subgrid のざっくりとした概念です。

実装方法

前提として、 HTML は基本的に以下の構造となっています。

<div class="container">  <!-- 親 Grid -->
  <div class="content">  <!-- Subgrid -->
    <label for="hoge">ラベル</label>
    <div class="field"> <!-- Subgrid -->
      <div>
        <input id="hoge" />
        <p>必須項目です</p>
      </div>
      <div>
        <p>注釈文言</p>
        <p>注釈文言</p>
      </div>
    </div>
  </div>
</div>

ステップ 1

まずは、 display: grid; で大枠を作っていきます。

.container {
  display: grid;
  grid-template-columns: max-content auto; /* ラベルの最大幅 | 空き領域 */
  gap: 30px 20px;
}

この時点では、まだ左カラムも右カラムも存在していませんね。

大枠

ステップ 2

左カラムと右カラムに分かれるようにしていきましょう。

.content {
  display: grid;
  grid-template-rows: auto auto;
  grid-template-columns: subgrid;
  grid-column: span 2;
}

ひとつひとつの項目を覆う wrapper の columns に、 subgrid を指定します。
これによって、親 Grid の columns が子にも適用されました。
また、 grid-column: span 2; で、親 Grid の 1 トラック目と 2 トラック目の両方にまたがるように指定します。

そして、 rows にも auto auto で入力フィールドと注釈エリアの 2 トラック分の指定をしておきます。

それっぽくなってきました。

左と右を分ける

ただ、 wrapper の Grid を見ると、まだ適切に分割されているとは言えませんね。
この時点ではラベルの高さも連動していません。

content の Grid

ステップ 3

右カラムを入力フィールドと注釈エリアに分けてみましょう。

.field {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 2;
}

rows は親で分けておいた rows を引き継ぐので、 subgrid を用います。
また、 grid-row: span 2; で、親 Grid の 1 行目(入力フィールド)と 2 行目(注釈エリア)の両方にまたがるように指定します。

意図した分割になりました!

エリア分割

ここでやっと、ラベルの高さも入力フィールドの領域と一致しました。

ラベルの高さ

ステップ 4

仕上げです。ラベルが天地中央になるように、 align-self: center; を付与しましょう。

label {
  align-self: center;
}

完成!

ラベルの天地中央揃え

おわりに

入力フォームのデザインや仕様によって実装要件も変わってくると思いますが、 subgrid のアレンジ次第で大抵のレイアウトに対応可能な内容になっています。

ちなみにこちらは、subgrid とは?の章で用いた subgrid 解説用の画像を AI 生成しようとした際に生み出された画像です。subgrid おじさんと名付けました。
subgrid は確かに難解なのですが、 subgrid おじさんを爆誕させるに至った生成ロジックを考察するよりははるかに簡単だと思いますので、今まで馴染みがなかった方もこれを機に subgrid にも触れてみてはいかがでしょうか。

subgrid おじさん

株式会社ZOZO

Discussion

junerjuner

むしろバリデーション領域を含めない input の高さに合わせた方が左のラベルが上下しなくて良いのでは……?