i-Vinci TechBlog
株式会社i-Vinciの技術ブログ

HTML とユーザビリティについて考える

皆さんこんにちは。i-Vinci の下位です。

最近暑かったり寒かったりで気候が安定しませんね。

寒いと指がかじかんでしまうので仕事が捗りません。
暑いと単純に集中力が落ちるのでやっぱり仕事が捗りません。

早く春の様な暖かい気候で安定してほしいものです。
安定したお仕事のために!
まぁ暖かくなったらなったで睡魔との戦いが始まるのですが

本日のテーマ

さて、本日のテーマは HTML です。

Web コンテンツ作成の土台を担う重要な言語で、Web アプリ開発をするなら避けて通れない技術です。

HTML はマークアップ言語という種別で、アプリエンジニアの主戦場となるプログラミング言語とは若干毛色が異なります。
私自身あまり得意でないですし、苦手意識を持っている人も割と多いです。(※観測範囲での話)

苦手意識を持っている人が多いのであれば、HTML をさくっと書ける人はヒーローです。
これは習得するしかないですよね?
(※くどいようですがあくまで観測範囲での話です)

今回はそんな HTML について、よくある入力フォームを題材にしつつ、実装コードと操作感を意識しながら語ってみることにします。

余談ですが、HTML の正式名称は「HyperText Markup Language」といいます。
ちょっと心がくすぐられる響きです

参考:HyperText Markup Language-Wiki

よくある入力フォーム

ということで、サンプルフォームを用意しました。
チェックボックス入力がある一般的な入力フォームです。(※CSS 実装は割愛)
サンプルフォーム

このフォームに対して、チェックボックス絡みの課題・改善方法を上げていきましょう。

問題点

提供した入力フォームは下記の課題があります。
1 つずつ改善方法を探っていきましょう。

  • 得意言語
    • チェックボックスのクリック有効範囲が狭く押下しづらい
  • 適当なグリッド
    • 行毎のチェックボックスのクリック有効範囲が狭く押下しづらい
    • 一括チェックをしたいが、1 つずつ押下する必要がある

課題 1:チェックボックスのクリック有効範囲が狭く押下しづらい

クリック範囲が狭すぎる問題です。
実は開発現場でも非常に遭遇率が高かったりします。

※四角のチェックボックス箇所だけが有効範囲です。狭い!

実装コードはこんな感じです。

<input name="prog-lang" type="checkbox" value="0" />JavaScript
<input name="prog-lang" type="checkbox" value="1" />TypeScript
<input name="prog-lang" type="checkbox" value="2" />CoffeeScript

こちらの改善方法は明確で、クリック範囲を広くしましょう。
表示名部分をリテラルから label タグに修正することで文字部分の押下にも対応するようになります。
(※label タグは押下イベントを関連するタグに伝播させる特性があります)

<!-- Case01 labelでinput+名称リテラルを括ることで解決可能 -->
<label> <input name="prog-lang" type="checkbox" value="0" />JavaScript </label>

<!-- Case02 固有IDを振ることでもlabelと紐付けが可能 -->
<input id="lbl-ctrl" name="prog-lang" type="checkbox" value="1" />
<label for="lbl-ctrl">TypeScript</label>

課題 2:行毎のチェックボックスのクリック有効範囲が狭く押下しづらい

グリッド内のチェックボックスが押下しづらい問題です。
こちらも本質は課題 1 と同様です。

※行ごとのチェックボックスは行レコードの更新・削除制御で頻出します。

下記、実装コードです。
tbody 配下を抜粋しています。

<tr>
  <td><input name="" type="checkbox" value="" /></td>
  <td>こういうテーブル、よくありますよね</td>
  <td>テスト</td>
</tr>

実は、課題 1 と同様に label で括れば解決というわけにはいきません。
というのも、label はインライン要素というグループに属している為、横幅・縦幅という概念を持ちません。
その為、label タグの大きさは小要素のチェックボックスのサイズに依存します。

反面、親要素となる td タグはブロック要素の為、横幅・縦幅の概念を持ちます。
ブロック要素・インライン要素の違いによる表示領域の違いが押下範囲のミスマッチに繋がっています。

参考:インライン要素とブロック要素

ともかく、今回はセル範囲(td タグ)の領域押下でチェックボックスを有効化したいので、目的を達成できません。

ではどうするか。
label タグをブロック要素として振る舞わせ、横幅を最大にすれば良いです。

では実装です。
下記変更を加えてみましょう。

  1. チェックボックスを label で括る
  2. label タグに[display: inline-block]を付与する
  3. label タグに[width: 100%]を付与する
<tr>
  <td>
    <!-- display: inline-blockをつけることでブロック要素の振る舞いが可能になります -->
    <label style="display: inline-block; width: 100%;">
      <input name="" type="checkbox" value="" />
    </label>
  </td>
  <td>こういうテーブル、よくありますよね</td>
  <td>テスト</td>
</tr>

課題 3:一括チェックをしたいが、1 つずつ押下する必要がある

全部チェックするのが ~~面倒~~ 大変、という問題です。
こちらは HTML のみで解決するのは難しいと考えます。

ということで、ここは JavaScript 大先生に処理してもらいましょう。
~~頼みますよ先生! (わかる人にはわかるネタ)~~

こんなスクリプトを定義して、チェックボックス列のヘッダを連打してみましょう。
一括トグル実装が出来る...筈です。

// チェックボックスのヘッダ要素にクリックイベントを設定
const triggerArea = document.querySelector(&#039;thead > tr > th&#039;);
triggerArea.dataset.type = &#039;check&#039;;

triggerArea.addEventListener(&#039;click&#039;, () => {
  // 一括チェック
  const prop = triggerArea.dataset.type === &#039;check&#039;;
  [...document.querySelectorAll(&#039;tbody input[type=checkbox]&#039;)].forEach(
    (d) => (d.checked = prop)
  );

  // 全選択・全クリアの切り替え
  triggerArea.dataset.type = prop ? &#039;clear&#039; : &#039;check&#039;;
});

改善後の入力フォーム

前述の改善策を盛り込んだ HTML はこちらです。
サンプルフォーム(改善後)

まとめ

今回は HTML をテーマに上げて、入力フォームと課題の改善方法を取り上げました。
押下範囲を拡げたい、という要望はよく有りますが、HTML レベルで対処可能ということがおわかりいただけかと考えます。
(勿論 CSS、Javascript でも対処可能です)

当記事で HTML に興味を持っていただけたのなら、是非とも次は HTML を作ってみましょう。
洗練された HTML の記述が出来れば、CSS のスタイリング・Javascript の制御等、フロント周りの世界が変わること間違いなしです!