1 ポイント 投稿者 GN⁺ 1 시간 전 | 1件のコメント | WhatsAppで共有
  • HTML のリストは視覚的な見た目ではなく、意味と相互作用の方法で選ぶべきであり、コントロール・順序・説明・メニュー・非順序リストに分かれる
  • 固定された選択肢には <select>/<option>、候補入力には <datalist> が適切であり、multipleoptgroupsizevalue の動作を区別して理解する必要がある
  • <ol> は順序を入れ替えると意味が変わる手順・出来事・連続体に使い、reversed は番号だけを逆順にするもので、実際の項目順は変えない
  • <dl> は HTML5 で定義リストを超えて説明リストへと拡張され、用語と値、メタデータ、JSON デバッグのようなキー・バリューの組に適している
  • <menu> はツールボタンのようなコマンドの一覧に使い、nav とは意味と許可されるコンテンツが異なり、それ以外の一般的なリストは <ul> が担う

コントロールリスト: <select>/<option><datalist>

  • フォームでもユーザーが相互作用する リスト を構成できる
  • 固定された選択肢は <select><option>

    • ユーザーがリスト内の項目だけを選べるようにしたい場合は <select><option> を使う
    • 言語リストの例では、Select a LanguageEnglishFrenchSpanishPortuguese といった <option><select name="languages"> の中に配置する
    • デフォルトの <select> は、ちょうど 1 つの選択肢だけを選ばせる
    • 複数項目を選べるようにするには multiple 属性を追加する
      • multiple を使うとリスト表示が変わってすべてのオプションが見えるようになり、ユーザーは Shift または Cmd + クリックで複数項目を選択できる
      • 実際に selectoption を使えば、role="listbox" の付いたリスト要素に aria-multiselectable を手動で付けなくても、ブラウザのデフォルトセマンティクスが処理してくれる
  • 関連するオプションは <optgroup> でまとめる

    • 言語を語族ごとにまとめたいなら、<optgroup> でオプションの一覧をグループ化する
    • 例では GermanicRomanceCeltic という label を持つ <optgroup> を作り、各グループに EnglishFrenchSpanishPortugueseIrishWelsh を配置する
    • 特定の下位グループを選択できないようにしたい場合は、その <optgroup>disabled 属性を追加する
    • 例では Celtic グループに disabled を付け、IrishWelsh を含むグループを無効化している
  • 標準の HTML 機能で改善する

    • グループ間に視覚的な区切りが必要なら、<select> 内で許可されている <hr> を使える
    • size 属性は一度に表示する項目数を制御するので、長いリストで役立つ
    • sizeoptgroup を一緒に使うと、グループラベルも表示領域を消費する
    • 例では <select name="languages" size="4" multiple>GermanicRomanceCelticAfroasiatic の各グループと、グループ間の <hr /> を入れ、HebrewArabic まで含めている

候補リスト: <datalist>

  • ユーザーにリストからの選択を強制するのではなく、リストを 候補として提示したいなら <datalist> を使う
  • <datalist> は 2 段階で接続する
    • <datalist> を作成し、id を付与する
    • 対応する <input>list 属性にその id の値を入れる
  • 言語候補の例では、<datalist id="languages"> の中に EnglishFrenchSpanishPortugueseIrishWelshHebrewArabic の各オプションを置き、<input name="language" list="languages"> で入力フィールドと結び付ける
  • <option value> の動作

    • <option> のデフォルト値は囲まれたテキストであり、value 属性があるとその値がデフォルト値を上書きし、テキストはラベルのように振る舞う
    • <select> ではユーザーはテキストだけを見るので大きな問題にはなりにくいが、<datalist> ではユーザーがラベルを見て選んだあと、入力欄には value が入るため混乱を招くことがある
    • 例で <option value="cy">Welsh</option> を選ぶと、ユーザーには Welsh が見えるが、入力には cy が入る
    • <datalist> を使うときは、挿入される値がラベルではなく value であることを前提にすべきである
  • 複数の入力タイプと組み合わせる

    • <datalist> はテキストオプション専用ではなく、ほかの input タイプとも組み合わせて使える
    • 週単位の選択例では、<input type="week" name="week" id="camp-week" min="2026-W2" max="2026-W51" list="preferred-weeks" /><datalist id="preferred-weeks"> を接続する
    • 候補の週は 2026-W222026-W232026-W242026-W25 である
  • <input type="range"> と組み合わせる

    • <datalist> は文字列値だけに限定されず数値でも動作するため、range 入力と組み合わせれば、範囲上にラベル付きの地点を作れる
    • チップ率入力の例では、<input type="range" name="tips" id="tips" min="0" max="50" step="1" list="recommended-tips" /><datalist id="recommended-tips"> を接続し、10%18%30%45% のラベルを置く
    • Chrome 系では @supports (x: attr(x type(percentage)))attr()label 値を読み取り、type() で値をパーセンテージとして宣言したうえで、オプションを position: absolute で配置する
    • Firefox 向けの方法では @supports not (x: attr(x type(percentage))) を使い、値は ::before で表示される
    • この方法は、すべてのブラウザが同じように動作したり、画面上で同一に表示されたりすることを保証するものではない

順序リスト: <ol>

  • 特定の順序で読む必要がある項目の集まりには <ol> を使う
  • 項目の横に数字を表示したいかどうかではなく、項目の順序を入れ替えると リストの意味が変わるかどうかが基準になる
  • <ol> に適したコレクションは、アルゴリズム、出来事の連続、増加または減少する連続体上の項目、レシピ、アルファベット順の一覧である
  • バナナブレッドのレシピ例では、オーブンの予熱と型への油塗り、材料を混ぜる、生地を流し込む、60 分焼くまたはつまようじがきれいに出てくるまで焼く、ワイヤーラックで冷ますという順序を <ol> で表現する
  • アルファベット順の材料一覧もアルファベットという連続体に従うため <ol> に該当し、baking sodabananasbrown sugarbuttereggsfloursalt の順に並べられる
  • 順序リストと非順序リストのネスト

    • よく構造化された順序リストは、ブラウザでのレンダリングを見なくても、何がどの順で起こるべきかを読み取れる
    • レシピの例では、上位のステップに <ol> を使い、ステップ内で順序が重要でない項目は <ul>、再び順序が重要な下位ステップは <ol> としてネストする
    • 構造としては PrepareMixPourBakeCool の上位順序を保ちつつ、PrepareBake の中の並列項目は <ul> で、MixCool の中の手順は <ol> で表現する
  • reversed

    • reversed 属性は番号付けの順序を昇順から降順へ変える
    • 実際のリスト項目の順序は変えない
    • most to least のように、多いものから少ないものへ見せる材料と分量の一覧に使える
    • 例では <ol reversed>eggs (2)flour (2 cups)bananas (2) (mashed)brown sugar (¾ cup)butter (½ cup)baking soda (1 teaspoon)salt (¼ teaspoon) を入れる
  • JavaScript で実際の項目順を逆にする

    • リストを実際に逆順にするには、JavaScript で li の子要素を逆順に再配置し、reversed 属性をトグルできる
    • 例の関数では list.querySelectorAll('li') の結果を配列にし、.reverse() した後、list.innerHTML = '' で空にして list.append(...children) で再び追加する
    • 最後に list.toggleAttribute('reversed') を呼び出す
    • 例のイベントでは orderedList.addEventListener('dblclick', (evt) => { reverseList(orderedList) }) により、ダブルクリック時に反転を実行する
  • start

    • start 属性は、1 つの巨大なリストの代わりに複数の順序付きリストへ分割するとき、番号の連続性を維持するために使う
    • バナナブレッドのレシピ例では、Prepareul のままにし、Mix<ol start=2>Pour<ol start=5>Cool<ol start=7> のように、続きのステップ番号を各リストに指定する
    • 途中に 6: Bake のような非順序リストで表現されたセクションがあっても、その後の Coololstart=7 で始めれば、手順全体の番号の流れを維持できる

説明リスト: <dl><dt><dd>

  • 説明リスト(description list) は、すべての内容を olul に無理やり押し込まなくても済むようにしてくれるリスト型である
  • HTML 4 の定義リスト

    • HTML 4 では description list ではなく 定義リスト(definition list) と呼ばれており、定義を提供する狭い用途に合わせられていた
    • 構造は、定義する用語である <dt> と、定義内容である <dd> から成り、意味的に正確に使うには定義される用語を <dfn> で囲む
    • 例では throwyeet を同じ定義に結び付け、no capbet にはそれぞれ定義を付けている
      <dl>
        <dt><dfn>throw</dfn></dt>
        <dt><dfn>yeet</dfn></dt>
        <dd>Verb. To discard at a high velocity</dd>
        <dt><dfn>no cap</dfn></dt>
        <dd>Interjection. Expresses authenticity and truthfulness, sometimes surprise.</dd>
        <dt><dfn>bet</dfn></dt>
        <dd>Interjection. Expresses agreement and affirmation.</dd>
      </dl>
    
  • HTML5 で広がった意味

    • HTML5 では定義だけに限定されない 説明リスト となり、「用語と値の集合」があるときに使えるようになった
    • HTML5 では、関連する <dt><dd> をまとめるために、非意味的ラッパーである <div> が許可されている
    • ブラウザエンジンの例では、ChromeOperaBraveEdgeBlink-based browsers にまとめ、FirefoxTorLibrewolfGecko-based browsers にまとめている
      <dl>
        <div class="dl-item">
          <dt>Chrome</dt>
          <dt>Opera</dt>
          <dt>Brave</dt>
          <dt>Edge</dt>
          <dd>Blink-based browsers</dd>
        </div>
        <div class="dl-item">
          <dt>Firefox</dt>
          <dt>Tor</dt>
          <dt>Librewolf</dt>
          <dd>Gecko-based browsers</dd>
        </div>
      </dl>
    
  • メタデータと JSON デバッグ

    • 事実とラベルの連なりであれば、メタデータの表示に説明リストを使うのが適している
    • ユーザープロフィールも <dl> に入れられ、例では First FrankLast TaylorAge 44Job WriterHandle Paceaux<dt><dd> の組で表現している
    • 単一ページアプリケーションにおける JSON デバッグ 用途でも説明リストを使える
    • DebugJson の例では、オブジェクトの各 key, valueObject.entries(obj) で走査し、キーは <dt><var>...</var></dt>、値は <dd><code>...</code></dd> としてレンダリングする
    • 値がオブジェクトで配列でない場合は DebugJson.createDl(value) を再度呼び出してネストされた <dl> を作り、それ以外の値は value.toString()<code> の中に入れる
      const debugJson = new DebugJson({foo: 'bar', arr: ['a', 'b'], car: 1}, '.container')
      debugJson.render();
    
    • 説明リストは キー・バリューの組 という要件に幅広く適合する

メニュー: <menu>

  • menu 要素はコマンドの一覧を表し、コンテンツのレンダリングよりもインタラクティブな Web により近い
  • menu は、リッチテキストエディタのテキスト修正コントロールのような「ツール」に当たるボタンの一覧に向いている
  • リッチテキストエディタの例では、StrongEmphasizeStrike ボタンを menu 内の li に配置する
  <menu>
    <li><button onclick="strong()">Strong</button></li>
    <li><button onclick="emphasize()">Emphasize</button></li>
    <li><button onclick="strike()">Strike</button></li>
  </menu>
  • HTML 仕様上、これは ツールバー(toolbar) 用途であり、インタラクティブなページでツールボタンがある場所は menu に入る可能性が高い
  • 動画コントロールの例も menu に入り、buttoncommandfor="vid-123"command="--play"--mute--fullscreen を持たせる
  <div class="player player--video">
    <video source="whatever.mp4" id="vid-123"></video>
    <menu>
      <li><button commandfor="vid-123" command="--play">Play</button></li>
      <li><button commandfor="vid-123" command="--mute">Mute</button></li>
      <li><button commandfor="vid-123" command="--fullscreen">Fullscreen</button></li>
    </menu>
  </div>
  • menu を使えば、非順序リストに aria-role="menu" を追加する必要はない
  • li が 2 つのコンテナにしか入らないと思い込まない

    • ナビゲーション内のリスト項目を一般的なリストのように見せたくないなら、menu li に対しても同じ処理が必要である
    • スタイルシートの先頭で、nav li だけでなく menu li も含めて list-style-typetext-indentmargin を初期化する
      nav li,
      menu li {
          list-style-type: none;
          text-indent: 0;
          margin: 0;
      }
    
  • <nav><menu> は別物

    • nav は単にリンクが入った menu ではなく、意味と許可されるコンテンツが異なる
    • nav は、ユーザーに「どこかへ移動することに関する複数の項目」を提供する意味を持つセクション要素である
    • nav<p><h1-6> のような段落や見出し、そして <ul><ol><menu> のようなリストを含められる
    • menu は、ユーザーに「できることの一覧」を提供する意味を持つリスト要素であり、リスト項目である <li> だけを許可する
    • menunav は相互排他的な選択肢ではなくmenunav の中に入れられるが、navmenu の中には入れられない

非順序リスト: <ul>

  • ul は、ほかのリスト型や nav では解決できない残りのリスト要件を受け持つ 包括的なリストである
  • 以前の HTML では、順序付きリストと非順序リストの違いは、数字か箇条書きかといった視覚的差異に近かった
  • 現在はアクセシビリティ、スクリーンリーダー、検索エンジン最適化を考慮するため、視覚的表示よりも 順序が意味を持つかどうか に注目すべきである
  • バンドメンバーの一覧は順序が重要ではないため ul に該当する
  <h3>Beatles</h3>
  <ul>
    <li>John Lennon</li>
    <li>Paul McCartney</li>
    <li>Ringo Star</li>
    <li>George Harrison</li>
  </ul>
  • バンド名の一覧も非順序リストとして表現できる
  <ul>
    <li>Beatles</li>
    <li>Rolling Stones</li>
    <li>Van Halen</li>
    <li>Foo Fighters</li>
  </ul>

1件のコメント

 
GN⁺ 1 시간 전
Hacker Newsのコメント
  • 例を試しただけでも、datalist は Mobile Safari ではあまりうまく動かないように見える
    これほど大きな市場で互換性の問題があるなら、実際のところ使う価値のあるシナリオはほとんどないと言えてしまうかもしれない

    • 望んではいなかったけれど、まさに必要だった 現実の冷や水 のような情報だ

      10年以上前に、UI でかなり攻めた入力候補ウィジェットを使うプロジェクトをやったことがあり、そのときは jQuery プラグインを使っていた
      フロントエンドで最も複雑な部分で、実質的にそのプロジェクトで jQuery を使う主な理由だった

      この記事を読みながら、そのフロントエンドを軽量な最小 JS 版として作り直すのは朝飯前だろうと思ったが、ユーザーの端末に自分の環境をそのまま配送できるわけではない以上、現実はそうではない
      それでも最近の HTML 仕様 に含まれている機能はかなり印象的だ
      高校のときに XHTML を読んで以来、仕様の変化をほとんど追えていなかったので、ときどき何が変わったのか見直したほうがよさそうだ
      ただ、ブラウザ互換性は当時も今も相変わらず頭痛の種だ

    • datalist の例 は自分の iPhone では確かに動く
      ネイティブ iOS キーボード上のオートコンプリート候補領域に統合される
      ただし、すべての候補を見て回る方法はなく、そもそもそれが datalist の想定された使い方でもない気がする

      ただ、groupdisabled 属性は確実に動いていない

    • Android の Firefox でも動かない

    • 初めての職場で働いていたずいぶん前には、Firefox で datalist が動かず、そのせいで Firefox が対応ブラウザ一覧から外された

      Chrome 以外のブラウザをサポートしようとすると、長いこと問題になってきた機能だ

    • iOS の GBoard と一緒に使うとうまく動かない

  • optgroupdisabled 属性を追加して一部のオプションを選べなくする例は、Mobile Safari では壊れているようだ
    実際には無効化されず、無効項目もそのまま選択できてしまう

    • 最新の Safari では動くはずなので、壊れているというより妙な状態に近い

      https://caniuse.com/mdn-html_elements_optgroup_disabled

      Safari のバグ の可能性がありそうだ

    • 基本的なこと以上に ネイティブ HTML を使いにくい理由はこういうところにある
      十分に読み込んで確信を持ってこういう記事を書けるだけ知っていても、コメント欄には結局ブラウザやデバイスの組み合わせごとの奇妙な挙動、制限、未対応情報が付いて回る

      div まみれは反対側に振り切りすぎた選択かもしれないが、それでも少なくとも奇妙な挙動や限界はかなり一貫していて目に見えやすい
      自分で書いたものやフレームワークが生成したものと、より一貫して噛み合うからだ

  • 面白くて包括的な記事だ

    残念ながら今では HTML を学ばずに React に直行する開発者 が多く、今や LLM まであるので、HTML をまったく学ばない可能性も高い

    そのため、単純な HTML で十分な場面でもまず React コンポーネントを探すことになる

    • それでも問題ないと思う

      最初に XML を使わなければならなかった頃は、XML 仕様 を学んで自分で出力しなければならなかった
      シリアライズライブラリが事実上なかった時代だ
      その後の世代が XML、のちには JSON を交換形式として使いながらも完全には学んでいないのを見てきたが、特に問題は起きなかった

      AJAX も最先端の流行語から、略語の意味を誰も知らない段階へ移り、今ではその用語自体をあまり認識していない人がほとんどだ
      AJAX は死んだのではなく、あまりに当たり前になって、もはや別の言葉が要らなくなっただけだ

    • 自分の問題は、20年前に HTML を徹底的に学び、その後どう変わり改善されたのかは偶然少しずつ知るだけだったことだ
      CSS はなおさらそうだ

    • 正直、HTML は面倒だ

      たとえばコントロールの一部をスタイルする HTML 的なアプローチは 疑似クラス を使うことだが、ブラウザごとにセレクタが違うこともある
      そうなると本当に正しく動くのか分からないので、ブラウザ別テストをしなければならない

      React のほうが簡単なだけでなく、より信頼できる
      React と div 群で作れば、すべてのブラウザで同じように動くだろうと見込める

  • 良い内容だが、datalist に期待しすぎてはいけない
    実用的に使うには 接続ポイント が足りず、小さなプロトタイプ以上の用途には向いていない

    • オートコンプリート候補に datalist を使ってみたら、とてもよく動いた
    • 昔 datalist で コンボボックス を作ろうとしたことがある気がするが、うまくいかなかった
  • HTML リンターが本当にこうした違いを見分けるのに役立つのか気になる
    この種の セマンティックタグの選択 を強制できるリンターがあるのかも知りたい

    • セマンティックタグを強制するという感覚はあまりしっくりこない
      HTML は何よりも作者が創造的に使えるよう作られているもので、特定のタグを別のタグより強制するのはおかしいと思う
      アクセシビリティは重要だが、制約はすでに十分多い

    • 自分が知るいちばん近いものは https://github.com/kristoff-it/superhtml#diagnostics

      SuperHTML は文法だけでなく、要素のネストや属性値も検証する
      HTML 仕様全体を検証コードに実装した他の言語サーバーはない

  • 今日初めて知った
    どうしてもっと多くのフレームワークがこれを活用しないのか不思議だ

    • ユーザー体験の観点では、普通のリストと同じだからだ
      コードを理解する助けになるなら使ってもよいが、ブラウザの アクセシビリティツリー やその他すべての面では、ただの順序なしリストにすぎない

      それがアクションの一覧だと伝えるには ARIA 属性を追加しなければならない
      記事では role=menu に触れているが、それだけでは不十分で、各項目にも menuitem ロールが必要だ
      WAI Authoring Practices Guide はロールと期待されるインタラクションを説明しているが、コード例をそのままコピーしてはいけないし、とくにナビゲーションメニューにこのロールを使ってはいけない

      https://www.w3.org/WAI/ARIA/apg/patterns/menubar/

    • 賢い人は難しい HTML なんて学ばず、div をいくつも並べて解決する

    • 最近の HTML には面白い機能がたくさんある

      ある要素が何をすると思うか人に尋ねるのが好きだ
      自分も最初はまったく当てられなかった

  • 数年間フロントエンドリードをしていたのに知らなかった有用な情報が多い
    会社でも確実に使い始めることになりそうだ

  • デザイナーたちが datalist のデフォルト外観 を気に入ってくれさえすればよかったのに

    • 自分の経験では、スタイルのカスタマイズ不足 がネイティブ HTML 機能を使う最大の障害だ
  • ブログ記事自体はとても良いのに、ブログ内の全記事一覧を一度に見る方法がどうしても見つからない

    https://blog.frankmtaylor.com/archive ではないし

    https://blog.frankmtaylor.com/archives でもなく

    https://blog.frankmtaylor.com/posts も違う

    https://blog.frankmtaylor.com/all もない

    https://blog.frankmtaylor.com/blog でもない

    ブックマークが1万件を超える人も多いのだから、説明や本文抜きでこれまで書いた全記事を並べる 単一の一覧ページ があると本当に便利だと思う

    • 言っているのは サイトマップ のことではないだろうか
      たいていのブログには、すべての記事を列挙した sitemap.xml がある

      それに、235本の記事を全部ざっと見たい理由も少し気になる