1. はじめに
こんにちは!
今回は Bootstrap の話をしたいと思います。
画面が広い時は横幅を有効に活用して1画面に表示する情報量を多く(縦スクロール量を小さく)、画面が狭い時は各入力欄を横幅いっぱいに伸ばして入力しやすくしたいという目論見がありました。
Bootstrap で配置といえばグリッドシステムですが、各項目(ラベルと入力要素のセット)はグリッドで配置します。
これで要件は凡そ満たせるのですが、今回はそこからさらに一歩進んで、画面サイズが大きい時はラベルを入力要素の横(左)に、小さい時は縦(上)に配置したいと思いました。
入力要素の上または左のいずれかにラベルを配置するのは難しくありません。
しかし、画面サイズに連動して「適宜に」配置となれば話は別です。
今回はそれが実現できるかどうか試してみました。
完成イメージは以下です。
2. 試してみる
グリッドシステムは、大まかな配置はともかく、ラベルと入力要素の関係のような細かな配置には向いていません。
したがって、ラベルの配置はグリッドシステムではなく、他の手段、フレックスボックス(Flex)を使って実現することになります。
コードは以下になります。
<div class="container">
<div class="row">
<div class="col-sm-9 col-md-6 col-lg-4">
<div class="mb-3 w-100">
<div class="d-flex flex-column flex-sm-row column-gap-2 align-items-sm-center">
<label class="form-label text-nowrap" for="text1">ラベル1</label>
<div class="col">
<input type="text" id="text1" class="form-control" placeholder="テキスト1">
</div>
</div>
</div>
</div>
<div class="col-sm-9 col-md-6 col-lg-4">
<div class="mb-3 w-100">
<div class="d-flex flex-column flex-sm-row column-gap-2 align-items-sm-center">
<label class="form-label text-nowrap" for="text2">ラベル2</label>
<div class="col">
<input type="text" id="text2" class="form-control" placeholder="テキスト2">
</div>
</div>
</div>
</div>
<div class="col-sm-9 col-md-6 col-lg-4">
<div class="mb-3 w-100">
<div class="d-flex flex-column flex-sm-row column-gap-2 align-items-sm-center">
<label class="form-label text-nowrap" for="text3">ラベル3</label>
<div class="col">
<input type="text" id="text3" class="form-control" placeholder="テキスト3">
</div>
</div>
</div>
</div>
</div>
</div>
ここで注目すべき箇所はラベルとテキストボックスを囲む div の class に指定した d-flex flex-column flex-sm-row です。
この定義はフレックスボックスを利用した配置方法で、画面サイズが極小(xs)の時は積み重なる配置(column)、小(sm)以上の時は水平配置(row)になります。
ちなみに align-items-sm-center は画面サイズが小(sm)以上の時に、子要素(ラベルとテキストボックス)を垂直方向に中央配置する定義です。小(sm)以上に限定しているのは、極小(xs)の時にラベルが水平方向に中央配置されてしまうことを防ぐためです。状況を想像しにくい場合は align-items-sm-center を align-items-center に置き換えて動作を確認してみてください。
3. 少しだけ応用
ラベルの動的配置は実現できたため既に目的を達成していますが、続けてもう少し複雑な構造を試してみたいと思います。
上記のコードではラベルとテキストボックスが1対1でしたが、今度は1つのラベルに対し複数の入力要素が配置される場合を考えてみます。
例えば「期間」のような、開始と終了の日付を入力する場面を考えてみましょう。
よく目にする構成は、ラベル1つ、テキストボックス2つ、カレンダー(Datepicker)表示ボタン2つ、開始と終了の日付の間に「~」でしょうか。
Bootstrapでは input-group クラスを使うと、各入力項目が横に並んだ構造を簡単に作れます。
理想は以下のイメージのように、画面サイズによってラベルだけでなく入力要素が適切に縦または横に配置されることだと思います。
このような構造は、フレックスボックスをネストさせることで実現可能です。
コードは以下になります。
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-10 col-lg-9 col-xl-8">
<div class="mb-3 w-100">
<div class="d-flex flex-column flex-sm-row column-gap-2 align-items-md-center">
<label for="dateFrom" class="form-label text-nowrap">期間</label>
<div class="col">
<div class="d-flex flex-column flex-md-row">
<div class="input-group">
<input type="text" id="dateFrom" class="form-control" placeholder="開始日">
<span class="input-group-btn">
<button type="button" class="btn btn-light"><i class="bi bi-calendar3"></i></button>
</span>
</div>
<span class="input-group-text">~</span>
<div class="input-group">
<input type="text" id="dateTo" class="form-control" placeholder="終了日">
<span class="input-group-btn">
<button type="button" class="btn btn-light"><i class="bi bi-calendar3"></i></button>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
内側のフレックスボックスの定義(d-flex flex-column flex-md-row)でラベル以外の配置を制御しています。
画面サイズが小(sm)の時に、ラベルは横配置、入力要素は縦配置と異なる配置になります。
なお、テキストボックスとボタンの組み合わせについてはバラバラに配置されるのを避けるため、input-group クラスで囲んでいます。
※カレンダーのアイコンは Bootstrap Icons を使用しています。
4. おわりに
いかがでしたでしょうか。
この投稿が誰かのお役に立てれば幸いです。
余談ですが、テキストエリア(<textarea>)のように、高さのある要素に対し横配置のラベルを設定する場合は、align-items-sm-centerクラスの定義を外した方が見栄えは良いと(個人的には)思います。
5. 参考にさせていただいた情報
Bootstrap
https://getbootstrap.jp/






