LoginSignup
9
5

<br> と <br /> はどう違う? - ポリグロット・マークアップの幻想、他 HTMLのお話 5 選

Last updated at Posted at 2023-12-15

はじめに

この記事は 2023 年の MDN 翻訳 Advent Calendar 向けに作成したものです。

こんにちは。debiru です。XHTML の X は Extensible の Ex の音を表しているので eXtensible と表記すべきではない委員会から来ました。

さて、今日も今日とてネタが見当たらないので HTML のお話をいくつか紹介してみます。

HTML のお話 5 選

思いついた HTML のお話を 5 個くらい書いてみます。

1. a 要素と button 要素を使い分けよう

ユーザーがクリックして操作するものを divspan でマークアップしてはいけません。と言われて久しいものですが、マークアップしてはいけない理由は分かるでしょうか。

例えば div をボタン風に仕立てるためにクリックイベントを設定したとしても、マウスを用いずにキーボード操作しているユーザーがいた場合、ユーザーは div 要素を「クリック」できなくなってしまいます。なぜならキーボード操作によるフォーカスの対象にはならないからです。では、フォーカスの対象にするような JavaScript を書けばいいのでしょうか。もしかしたら実装が不十分で、また違う環境のユーザーが操作できない可能性が残ってしまうかもしれません。

HTML には専用のインタラクティブ要素が存在しています。クリック操作が想定されているものとして a 要素や button 要素があります。これらはデフォルトでキーボード操作によるフォーカスの対象となるので、クリックイベントを設定するだけで、マウスを用いないユーザーでも問題なく操作できることが期待できます。

では、クリックによる操作を実現したい場合は button 要素を使っておけば良いのでしょうか?答えは No です。button 要素には実現できない機能が存在しています。それはユーザビリティのあるリンク機能の提供です。

リンク機能の提供をする場合は button 要素ではなく a 要素を使いましょう。なぜなら、a 要素には、未訪問か訪問済みかの状態を表示しわけることができたり、ControlCommand キーを押しながらクリックする、あるいは「右クリック」でコンテキストメニューを表示することによって別タブでページを表示することを提供する機能があるためです。

MDN ページの言語切替メニューが表示されている。

Wiki システムから脱却し GitHub ベースで管理がされるようになった現在のデザインの MDN ページでは、ページの右上に言語切替メニューが存在しています。この言語切替ボタンがこれまで button 要素で実装されていたために、ユーザーは別タブで別言語のページを開くことができませんでした(button 要素でも別タブで開くことができる一部のブラウザを除いて)。

これはユーザビリティの低下を招いてしまっています。この問題については 2023 年 4 月に私が修正を提案し、8 月に a 要素での実装となるよう修正が行われました。

みなさんも、他の処理を伴わない単なるリンクが button 要素で実装されているものを見つけたら、a 要素で実装すべきことを提案しましょう。

2. <button><input type="button"> の違い、type 属性のデフォルト値について

input 要素の歴史は古く、HTML 2.0 時代には存在していました。この頃から基本的なフォーム機能が提供されており、Web ページ制作者はフォーム機能を利用することができました。

button 要素は HTML 4.0 で登場しました。input 要素によるボタン(type 属性値が button, reset, image などのもの)との違いは、button 要素が内容を持てる(空要素ではない)という点にあります。button 要素は input 要素によるボタンの拡張要素なのです。つまり、button 要素の方が高機能なのです。button 要素であれば、中身に「画像とテキスト」を同時に入れたり、画像に代替テキストを設定することができます。

そんな便利な button 要素ですが、歴史的な理由により、type 属性を省略した際のデフォルト値が submit になっています。これは、form 要素内に button 要素を設置した際に、type 属性を指定しない場合、ボタンのクリック操作によってフォームがサブミットされてしまうことを意味します。

JavaScript から操作する単純なボタンとして利用したい場合は type="button" を指定する必要があります。また、そのような混乱を避けるために、button 要素を利用する場合は、submit として利用する場合であっても、常に type 属性を明示的に指定するようにした方がよいでしょう。

みなさんも、type 属性値が指定されていない button 要素を見つけたら、type 属性を指定すべきことを提案しましょう。

3. <br><br /> はどう違う? - ポリグロット・マークアップの幻想

みなさんご存知の通り HTML (Hyper-Text Markup Language) はマークアップ言語ですが、HTML にはベースとなった SGML (Standard Generalized Markup Language) というマークアップ言語が存在しています。初期の HTML は SGML のサブセットとして定義され、HTML 4.01 までは SGML のサブセットとして HTML が構成されていました。

SGML には GML (Generalized Markup Language) という更にベースとなった言語が存在しています。SGML の歴史については SGML誕生のいきさつ - dsssl.info が詳しいです。

SGML には省略タグ機構や短縮タグ機構というものが存在しています。省略タグ機構の規則と HTML の DTD (Document Type Definition) によって、HTML 4.01 では一部の要素の開始タグや終了タグを省略することができていました。また、SGML では空要素(Empty Element, HTML5 では Void Element と改名された)は終了タグを省略しなければならないと定められていました。

SGML はタグの省略ができるなど自由度が高い反面、どの要素が空要素なのか判定できないと要素内容を正しく解析することが不可能でした。こうした問題を回避し、任意の用途向けに拡張することを容易にしたマークアップ言語として SGML のサブセットという形で XML (Extensible Markup Language) が登場しました。XML では全ての要素タグが省略できません。

HTML を XML ベースで定義しようという動きがあり、登場したのが XHTML 1.0 です。XHTML では XML に準拠した HTML を書くことになります。

ここで注目すべきなのが、空要素タグの書き方です。

  • HTML 4.01 - 終了タグを省略して <br> と書くことになっている。
  • XHTML 1.0 - 終了タグを省略せずに <br /> のように書く。

あれ?終了タグを書くということは <br></br> になるのではないでしょうか。しかしこれは旧来の SGML にあった「空要素は終了タグを省略しなければならない」に反します。

SGML には短縮タグ機構というものがあり、その一部に簡略終了タグ(NET; Null End Tag)と、さらに NET 可能開始タグ終了区切り子(NESTC; NET-Enabling Start-Tag Closer) と呼ばれるものがあります。NET の解説は SGML の短縮タグ機構 | 鳩丸よもやま話が詳しいのでそちらをお読みください。

結局、<br></br> は NET および NESTC により <br/> と書けるのでした。この短い形式の / が開始タグの括弧閉じで、> が終了タグそのものを表しているのです。しかし、<br/> のように要素名と / を繋げて書くと、br/ を要素名だと解釈してしまう User Agent が当時は存在していました。そのような User Agent が要素名を勘違いしないようにスペースを付与して <br /> のように空要素タグを記述するようになったのです。

これが <br><br /> の違いというか表記が分かれた経緯でした。HTML 4.01 では前者を、XHTML では後者を記述することになるわけです。

では、HTML5 ではどちらを記述するとよいのでしょうか。なお、もはや HTML5 は SGML ベースでも XML ベースでもありません。

答えは <br> です。なぜなら、XML に準拠した HTML5(XHTML5 とも呼ばれる)は幻想だからです。XHTML5 は Polyglot Markup(ポリグロット・マークアップ)とも呼ばれます。幻想とはいったい何のことでしょうか。私にも分かりませんが、幻想ということらしいです。それでもなお、XHTML5 を目指している人は <br /> のように記述すればよいでしょう。記述して悪い道理は一つもありません。

Markup Validation Service - W3C では、空要素タグを <br /> のように書くともはや "Trailing slash on void elements has no effect and interacts badly with unquoted attribute values." と言ってきます。

みなさんも、空要素タグを <br /> のように閉じているマークアップを見かけたら、<br> のように統一して書くことを提案しましょう。

4. HTML5 における dl 要素の進化と障壁

dl 要素の dl は何の略でしょうか。そう、Definition List(定義リスト)です。このような定義が身に付いた読者はどれほどいるでしょうか。いると嬉しいのですが。いや、しかし、ご存知の通り正しくは Description List(説明リスト)です。HTML 4.01 / XHTML までは前者でしたが、HTML5 で改定されたのです。

そして HTML5 では、di 要素(Description Item)こそ互換性の問題で採用されなかったものの、同等のグルーピングを可能にする dl 直下の div が採用されました。これは次のようなマークアップを可能にします。

<dl>
  <div class="di">
    <dt>Name</dt>
    <dd>Godzilla</dd>
  </div>
  <div class="di">
    <dt>Born</dt>
    <dd>1952</dd>
  </div>
  <div class="di">
    <dt>Birthplace</dt>
    <dd>Japan</dd>
  </div>
  <div class="di">
    <dt>Color</dt>
    <dd>Green</dd>
  </div>
</dl>

class="di" は必須ではありませんが、私はこの特殊な div に対しては class="di" を与えるようにしています。di 要素は XHTML 2.0 で提案された要素です。

このような div を伴うマークアップの dl 要素は文書構造として強力です。なぜなら以下のような tbody が存在しない table 要素と同等の構造を持つからです。display プロパティを駆使すれば、dl 要素のマークアップで表組レイアウトが実現できます。これは HTML 4.01 時代の dl 要素にはできなかったことです。

<table>
  <tr>
    <th>Name</th>
    <td>Godzilla</td>
  </tr>
  <tr>
    <th>Born</th>
    <td>1952</td>
  </tr>
  <tr>
    <th>Birthplace</th>
    <td>Japan</td>
  </tr>
  <tr>
    <th>Color</th>
    <td>Green</td>
  </tr>
</table>

しかし、HTML5 時代の dl 要素には障壁もあります。

HTML5 に起因した問題ではないですが、dl 要素はアクセシビリティツリー上の表現に問題があるのです。なんと、上記の dl 要素のマークアップを、「4 つの項目と説明」ではなく「8 つのリスト」と読み上げるのです。詳しくは dl/dt/ddのスクリーンリーダーの読み上げをなんとかする - ゆうてんを参照してください。

とはいってもこれはスクリーンリーダー側の問題として解決を望んだほうがよいでしょう。これを理由に dl 要素を使わないという選択をする人もいるようですが、せっかく dl 要素で表現できる幅が広がったのですから活用していきたいものです。

みなさんも、div を使わずに dl 要素タグでマークアップしている例を見つけたら、div でグルーピングすると幸せになれるよと提案しましょう。

5. fieldset 要素を活用しよう

フォームのマークアップにおいて、次のような例を考えましょう。

...
<h2>注文</h2>
<form action="..." method="post">
  <h3>注文者情報</h3>
  <ul>
    <li><label>氏名<input type="text" name="customer-name"></label></li>
    <li><label>郵便番号<input type="text" name="customer-zipcode"></label></li>
    <li><label>住所<input type="text" name="customer-address"></label></li>
  </ul>
  <h3>お届け先情報</h3>
  <ul>
    <li><label>氏名<input type="text" name="shipping-name"></label></li>
    <li><label>郵便番号<input type="text" name="shipping-zipcode"></label></li>
    <li><label>住所<input type="text" name="shipping-address"></label></li>
  </ul>
  ...
</form>

上記は一見、悪くなさそうなマークアップに見えますが、致命的な問題があります。スクリーンリーダーの利用者がキーボード操作しているような状況では、input 要素にフォーカスして、それに関連付けられたラベル文言が読まれますが、例えば 1 つ目の input 要素にフォーカスすると「氏名のテキスト入力」と読まれます。これでは、何に対する氏名なのか分かりません。

これを解決するのが fieldset 要素です。fieldset 要素を用いて次のようなマークアップをしてみましょう。

...
<h2>注文</h2>
<form action="..." method="post">
  <fieldset>
    <legend>注文者情報</legend>
    <ul>
      <li><label>氏名<input type="text" name="customer-name"></label></li>
      <li><label>郵便番号<input type="text" name="customer-zipcode"></label></li>
      <li><label>住所<input type="text" name="customer-address"></label></li>
    </ul>
  </fielset>
  <fieldset>
    <legend>お届け先情報</legend>
    <ul>
      <li><label>氏名<input type="text" name="shipping-name"></label></li>
      <li><label>郵便番号<input type="text" name="shipping-zipcode"></label></li>
      <li><label>住所<input type="text" name="shipping-address"></label></li>
    </ul>
  </fieldset>
  ...
</form>

legend 要素は fieldset 要素の最初の子でなければなりません。

このようなマークアップをしていると、スクリーンリーダーでは 1 つ目の input 要素にフォーカスした際に「注文者情報 氏名のテキスト入力」のように読み上げられることが期待できます。fieldsetlegend 要素は、input 要素などのフォームコントロールをグループ化すると同時に、フォームコントロールに対してそれが何に属する情報なのかを関連付けることができます。

fieldsetlegend 要素は地味ですがアクセシビリティを向上する上で非常に強力な道具になります。ぜひ積極的に利用しましょう。

みなさんも、fieldset を使わずに form 要素タグでマークアップしている例を見つけたら、fielset でグルーピングすると幸せになれるよと提案しましょう。

さいごに

ネタが思いつかなくて HTML 関連のトピックを A から Z まで順に思い付くだけ書こうかと思ったのですが、5 個書いただけでもこの分量になってしまったので私の構想は F で打ち止めとなりました。

PHP の var_dump() とかを直接出力するなら xmp 要素が便利だよとか書こうと思ったのですが、xmp 要素を知っていたという方はいますか。この記事を読んでいる HTML マニアな方なら知っているかもしれませんね。

それではまたお会いしましょう。

おわり。

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5