HTML解体新書を読んだ

はじめに

フロントエンドの開発に関わるようになり、薄々気づいていたけどもフレームワークの使い方やコンポーネント指向開発以上にhtmlそのものにまつわる悩みが増えました。
cssで幅を調整したり縦横に並べ替えたりといった作業の中で、いきあたりばったりに対応してしまうことがあるため、htmlの仕様を理解したく読んでみました。
読んだ本はこちらです: HTML解体新書-仕様から紐解く本格入門

 

知らないことばっかりだった、まだまだがんばります。

特に勉強になったこと

"内容モデル"

この概念を知っただけでもこの本を読んだ意味がありました。普段htmlでマークアップするときには、どの要素がどの要素に入るかを明確に理解してなくて、なんとなくこれはこの中だな、くらいでやってしまってました。
結果的に問題にならないとはいえ、divになんでも入るからdivを使えばいいわけではないというのに納得です。
また、書籍ではコラム程度にしか出てこないですがhtml上では「ブロック要素」「インライン要素」が言語仕様としては使われていないことに衝撃を受けました。cssの方言のようですね。正確には、html5から要素の分類が一新され、明確な1:1対応はなくなりました。
我々ウェブアプリケーションを実装する人々は、「この要素はブロック要素だから〜」みたくレイアウトのデバッグをするわけで、仕様を読む際の欠かせない前提知識です。

HTML Living Standardが読めそう

現行HTMLの基礎になっている概念をインプットできたのでHTMLの言語仕様であるHTML Living Standard も適宜参照できそうです。

 

レイアウトを作っているときに「ここに横に並べたいときどうすれば」となるので、そのときに扱っている要素の性質を仕様をもとに考えられるようになったかなと思います。

 

htmlをとっかかりにcssの仕様(Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification)も読めるようになったのでちまちま読んでいます。

 

考察: ウェブアプリケーションとhtml

書籍を通じて、htmlの要素(タグの種類)とそれの性質がよく使うものを中心に紹介されていました。そもそも、htmlはハイパーテキストマークアップするための規格であるので、文書には見出しがあって小見出しがあって段落があってその中にリンクが埋め込めて...といった、文書を書くためのツールキットの側面が強いです(もちろん広範なウェブ技術に対応するべく拡張はされていますが)。

 

昨今DXだ、デジタライゼーションだなどITに推進の機運が高まり続けていて、並行して個人が使えるコンピューティングリソースが潤沢になっています。すると、そのような有り余るリソースを土台にリッチな動きができるウェブアプリケーションの需要も高まり、UIを構成するhtmlには文書を作る以上の役割を担わせています。実際、UIを作っているとタグの並びと見た目があまり噛み合ってない状況の遭遇します。

 

本来ハイパーテキストマークアップする規格であったhtmlを入り口にjsを使ったapiコール、非同期での仮想DOM操作などなど飛び技を駆使していることを考えると、一周回ってそのレイアウトにこのタグを使うべきなのか?本来の用途に適しているか?を熟慮する必要性が高まっているなと感じました。ボタンクリックで出てくるドロップダウンをdivでやりきることはできるけど、アクテシビリティや本来の用途考えるとselectで良いケースがその一例です。

書籍で勉強になったこと

ここからは各章でなるほどと思ったことのメモです。

内容モデル(Content model)

ある要素がどのような要素に属することができるかは、ルールで決まっている。このルールのことを内容モデル(Content Model)と呼ぶ。

内容モデルには以下のようなものがある:
  • Metdadata
  • Flow
  • Phrasing
  • Sectioning
  • Heading
  • Interactive
  • Embeded
たとえば、以下のようにspanの中にpを定義できないのはspanの内容モデルがPhrasingであるから。
<span>
  <p>
    このネストはできない
  </p>
</span>
ウェブアプリケーションマークアップによく用いられるdivやp、ulはFlowコンテンツ。spanやstrong, codeといった段落内テキストを修飾するような要素はPhrasingコンテンツ。 以下のようなマークアップはFlowコンテンツにPhrasingコンテンツが含まれる例ということになる。
  <p>
    <span>text</span>
  </p>

補足: ブロックレベル要素とインラインレベル要素

ブロックレベル要素、インラインレベル要素はCSSの視覚要素レベルで、css視覚整形モデル とHTMLの内容モデルは本質的に異なる概念。 HTML5でレベル分類が一新され、HTML4でインライン要素とされていたものはPhrasingコンテンツとなった。ブロックレベル要素とされていたものはFlowコンテンツに相当するものの、 FlowやPhrasingも含むため1:1に対応しない。

htmlの主要な要素

セクショニング

sectionやnavを用いることで見出しに続くセクションを明示できる。見出し要素(h1 - h6)が入っているFlowコンテンツはsectionを使わずともセクショニングされる。
html要素2番目の子で、文書の表示する内容を示す。セクショニングルートになる。それぞれ、一つのhtmlに一つだけ含められる。

section

一般的なセクションを表現する。通常見出し要素を置くが、それができない場合はdivで囲って代用できる。

style

メタデータコンテンツ。metaやtitleと同じ内容モデルなので、`head`に置くことができる

グルーピング

blockquoteはFlowコンテンツで、文字をそのまま置くこともできる。pで囲った文字列をそのまま置くこともできる。

別のソースから引用されたセクションがここに表示されます。

整形済みテキスト

preは改行やスペースをそのまま維持した、整形済みテキストとして表示する。

ul li {
  list-style: none;
}

列挙

  1. ol、ulは自身とliのみ子要素になれる
  2. ol, ulは空でもよい
  3. liはFlowコンテンツ。他のFlowコンテンツないしはPhrasingコンテンツを含むことができる。

main要素

mainはその性質上、bodyに一つだけ存在することを想定した要素。hiddenで隠せば複数置くことができ、jsなどでmainの出し分けを行うユースケースを考えられる。mainはbodyの直下に置くこと。

div

divに特別な意味を持たないFlowコンテンツ。主にスタイルやレイアウトのために付与する使い方がある。

テキストレベルセマンティクス

テキストレベルセマンティクスはテキストをマークアップする用途で用いられ、すべてPhrasing contents。

テキストマークアップの要素

テキストレベルで修飾する、Phrasingコンテンツのマークアップ例。すべて対応するHTMLタグでマークアップされている。
  • 太文字にする
  • 強調
  • 小さい文字にする
  • 取り消し線
  • HTML
  • 特に重要ではないけど太くしたいテキストにはb要素を使う。
  • u要素を使えば下線がつきます。アクセシビリティを考えると、色以外によるリンクの見分けをしたいので可能なら使わない。
  • spanは、divと同じく特別な意味を持たない要素。他に有効なマークアップがないときに用いる。
  • const lazyMap = (arr, f) => {
      return () => (f)
    }

リンク関連

a

内容モデルはtransparent。親要素の内容モデルを引き継ぐので、divの子要素になっていればFlowコンテンツのように振る舞う。

<div>
  <a>
    <h1> 見出しでもクリックできる </h1>
  </a>
</div>

ウェブにおけるリンクは重要度が高い。そのためリンク要素のアクセシビリティには十分留意すること。

  • リンク先が推測できること e.g. "こちら" を避ける(here症候群)
  • リンクボタンはあくまでリンクなので、支援技術は "リンク" として認識する。

link要素

Metadataコンテンツで、終了タグがない、単独で存在できる要素。
  • linkはaと異なり、html文書が参照するリソースとの関係を表現する要素。リンク先リソースの種類はrel属性で指定される。
  • 使用できる文字列表現はHTMLリンクタイプに定義される。
  • 多くの場合、relはhrefと一緒に用いてリンク先の実体とそれの種類を設定する。
次の例は、HTMLリンクタイプをstylesheetにした典型的なマークアップ
  <link rel="stylesheet" href="./style.css">

テーブル

tableの内容モデルは複雑。thead, tbodyなどを子要素にできる。trを直接配置できるが、tbodyが補われる。

tr

テーブルの行を表現する。内容モデルはtd, thのみ。td, thはどちらもFlowモデル。ただしthの子孫にheader, 見出しを含められない。

キャプションは省略しても良い。
変更日 商品名 在庫数
商品1 50
商品2 70

caption

テーブルにキャプションをつける。省略可能。

フォーム

ユーザが入力した情報をサーバに送信する機能があり、そのための要素が存在する。ユーザがテキストを入力するパーツをフォームコントロールと呼ぶ。

スクリプティング要素

以前のブラウザはVBScriptが動くこともあったが、現在はJavaScriptの動作のみ想定されている。

script

scriptはほとんどの要素の子要素になることができ、Meta、Flow、Phrasingのどれでもある。内容モデルは複雑で、src属性が指定されているときは非置換要素になる。

script要素は複雑な経緯を持っているため、srcで外部リソースを読み込んで使うようにする。

src属性で外部リソースを読み込む際、asyncやdeferを用いることで読み込みの遅延を実現できる。defer属性を指定すると、htmlの解析を優先してスクリプトのロードを遅延させる。

noscript

ブラウザのスクリプトが無効の場合のフォールバックコンテンツを提供する。スクリプトが有効なら無視される。

属性、ARIA

ARIA(Accesible Rich Internet Applications)属性は、アクテシビリティを向上させるための属性で、任意のマークアップ言語と組み合わせることができる。

ARIA属性は、その特徴から3つに分類できる:
  • ロール
  • ステート
  • プロパティ

代表的なaria-*属性

aria-hidden[state]

支援技術に存在しないことを伝える属性。意図しない、ないしは冗長な読み上げをスキップさせられる。

aria-label[property]

要素にアクセシブルな名前を与える。例えば、アイコンボタンなどテキストから文脈を伝えづらいケースでは与えた名前によってアクションが明瞭に伝わる。

aria-labelledby[property]

aria-labelと同様の働きをするが、aria-labelledbyは要素のIDを指定する。

aria-haspopup

属性が指定された要素にポップアップがあることを伝える。視覚的にしかわからないドロップダウンの存在を提示できる。