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

# はじめに

この記事は [2023 年の MDN 翻訳 Advent Calendar](https://qiita.com/advent-calendar/2023/mdn-translation-community-japan) 向けに作成したものです。

こんにちは。debiru です。XHTML の X は Extensible の Ex の音を表しているので [eXtensible と表記すべきではない](http://lists.xml.org/archives/xml-dev/200802/msg00313.html)委員会から来ました。

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

# HTML のお話 5 選

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

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

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

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

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

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

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

![MDN ページの言語切替メニューが表示されている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178936/c44f9a19-4be7-0b0a-fbd8-0a7374d67432.png)

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

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

https://github.com/orgs/mdn/discussions/365

:::note info
みなさんも、他の処理を伴わない単なるリンクが `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` 属性を明示的に指定するようにした方がよいでしょう。

:::note info
みなさんも、`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](https://www.dsssl.info/learning_dsssl/01_introduction/01-01_sgml_history/) が詳しいです。

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 の短縮タグ機構 | 鳩丸よもやま話](http://bakera.jp/yomoyama/shorttag#section2-3)が詳しいのでそちらをお読みください。

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

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

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

```mermaid
flowchart LR
  GML --> SGML
  SGML --> HTML[HTML 4.01]
  SGML --> XML
  XML --> XHTML
  HTML5
```

答えは **`<br>`** です。なぜなら、XML に準拠した HTML5（XHTML5 とも呼ばれる）は幻想だからです。XHTML5 は [Polyglot Markup（ポリグロット・マークアップ）](https://momdo.github.io/html-polyglot/)とも呼ばれます。幻想とはいったい何のことでしょうか。私にも分かりませんが、[幻想ということらしいです](https://twitter.com/momdo_/status/1504330578052939776)。それでもなお、XHTML5 を目指している人は `<br />` のように記述すればよいでしょう。記述して悪い道理は一つもありません。

[Markup Validation Service - W3C](https://validator.w3.org/) では、空要素タグを `<br />` のように書くともはや "Trailing slash on void elements [has no effect](https://github.com/validator/validator/wiki/Markup-%C2%BB-Void-elements#trailing-slashes-in-void-element-start-tags-do-not-mark-the-start-tags-as-self-closing) and [interacts badly with unquoted attribute values](https://github.com/validator/validator/wiki/Markup-%C2%BB-Void-elements#trailing-slashes-directly-preceded-by-unquoted-attribute-values)." と言ってきます。

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

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

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

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

```html
<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` 要素にはできなかったことです。

```html
<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のスクリーンリーダーの読み上げをなんとかする - ゆうてん](https://zenn.dev/yusukehirao/articles/dl-dt-dd-wai-aria)を参照してください。

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

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

## 5. `fieldset` 要素を活用しよう

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

```html
...
<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` 要素を用いて次のようなマークアップをしてみましょう。

```html
...
<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` 要素にフォーカスした際に「注文者情報 氏名のテキスト入力」のように読み上げられることが期待できます。`fieldset` の `legend` 要素は、`input` 要素などのフォームコントロールをグループ化すると同時に、フォームコントロールに対してそれが何に属する情報なのかを関連付けることができます。

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

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

# さいごに

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

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

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

おわり。