Web●○○○○

HTML

HTML ・ えいちてぃーえむえる

文書の構造と意味をタグで記述するマークアップ言語。ブラウザが解釈してDOMを組み立てる。

✦ 30秒で試す — 航海タグを閉じ忘れても、ブラウザは文句ひとつ言わない組み立てた木で、divはどこに置かれる?予想してみる

概要

HTML(HyperText Markup Language)は、Webページの「構造」を記述するマークアップ言語です。見出し・段落・リンク・画像・フォームといった文書の部品を <h1> や <p> のようなタグで囲んで意味づけし、それらを入れ子にして一つの文書を組み立てます。プログラミング言語のように処理の手順を書くのではなく、「この部分は見出しである」「ここはリンクである」と宣言していく点が特徴です。

ブラウザは受け取ったHTMLを解析して DOM(Document Object Model)という木構造をメモリ上に組み立てます。このDOMに CSS が見た目を与え、JavaScript が動きを与える——Webフロントエンドの三層構造の土台がHTMLです。どれだけフレームワークが進化しても、最終的にブラウザへ届き、画面の骨組みになるのはHTMLである、という事実は変わりません。

なぜ生まれたか

1989年、CERN のティム・バーナーズ=リーは、研究所内に散らばる膨大な文書を相互に参照し合える仕組みを構想していました。当時も文書フォーマットは存在しましたが、「文書の中の一語から、別のコンピュータ上の別の文書へ直接跳べる」仕組み——ハイパーテキストを、ネットワーク越しに実現する共通言語がなかったのです。

そこで彼は、既存の文書記述言語 SGML を大幅に簡略化し、<a href="..."> というリンク(アンカー)を核に据えた HTML を設計しました。「誰でも書ける単純さ」と「URL で世界中の文書とつながるリンク」の組み合わせが決定的で、HTML は HTTP・URL とともに World Wide Web を成立させた三大要素になりました。

普及の裏で、もうひとつの課題が育っていきました。誰でも書けるぶん、世の中の HTML の大半は閉じ忘れや入れ子の誤りを含んでいて、ブラウザはそれぞれ独自の推測で表示していたのです。同じページがブラウザごとに違う木になる状態を、W3C は厳密な XML 文法の XHTML(誤りが1つでもあれば表示しない)で正そうとしましたが、既存のページが軒並み表示できなくなるため普及しませんでした。代わりに2004年、ブラウザ開発者たちが WHATWG を作り、のちに HTML5 と呼ばれる仕様(2014年に W3C 勧告、いまは WHATWG の HTML Living Standard)で「誤りを含む HTML をどう読むか」までを手順として一字一句定めました。いまの HTML は、壊れた入力に対しても、すべてのブラウザが同じ木を組み立てる言語です。

詳細

タグと属性、そして入れ子構造

HTMLの基本単位は要素です。<a href="/about">会社概要</a> のように、開始タグ・属性(href)・内容・終了タグで一つの要素をなし、要素の中に要素を入れ子にして木を作ります。文書全体は <html> を根とし、メタ情報を持つ <head>(タイトル、文字コードの宣言 <meta charset="utf-8">、CSS や JavaScript の読み込み指定など)と、実際に表示される <body> に分かれます。入れ子の箱はそのまま親子の木になり、ブラウザ内部の DOM も、CSSのセレクタも、JavaScriptによる操作も、すべてこの木を前提に動きます。

htmlbodyarticleh1星図の読み方p明るい星からa北極星同じ形htmlbodyarticleh1pah1 と p は兄弟文字列も「テキスト」として木の葉になる(図では省略)
入れ子の箱は、そのまま親子の木になる。箱の内側にあるものが子、並んでいるものが兄弟

ブラウザがこの木をどう画面のピクセルにするか——HTMLとCSSを解析し、スタイルを当て、配置を計算して塗るまでの流れ——はブラウザレンダリングの記事で扱います。HTMLを書く側として押さえておきたいのは、パース中に <script> に出会うとHTMLの解析が止まってJavaScriptが実行されること(そのため defer や async 属性で読み込みを制御する)と、<head> のスタイルシートが揃うまで描画が始まらないことの2点です。

「壊れても表示する」——寛容なパースの正体

HTMLパーサは、タグの閉じ忘れや誤った入れ子があってもエラーで止まりません。ただしそれは「なんとなく推測している」のではなく、HTML の仕様が定めた手順どおりに補い、組み替えているのです。<html>・<head>・<body> を書かなければパーサが補い、<table> の直下に <tr> を書けば間に <tbody> を挟みます。<p> の中に <div> を書くと、段落の中に箱は置けないので <p> はその手前で閉じられ、<div> は兄弟になります。<b> と <i> の閉じる順番が交差していれば、<i> を複製して開き直します。表の中に置き場のない文字は、表の手前へ追い出されます。

下の部品で確かめてください。左に HTML を打つと、右にブラウザ標準の DOMParser が組み立てた本物の木が出ます。書いたとおりの入れ子と違う部分——補われた要素、組み替えられた要素、複製された要素——に印が付きます。

⚡ 体験: HTML を打って、パーサが組み立てる本物の木を見る
ひな形

HTML(ただの文字列)

DOM(ブラウザで開くと、ここで本物のパーサが動く)

document<!DOCTYPE html><html>補われた<head>補われた<title>"星図"<body>補われた<h1>"知星図"<p>"星を"<b>"つなぐ"
ノード9補われた3組み替え0複製0空白のテキスト3
パーサが補った・複製した書いたときと親が変わったテキストノード

左の HTML を書き換えるか、ひな形を選んでください。右の木は、ブラウザ標準の DOMParser が実際に組み立てたものです。

この寛容さがWebの爆発的普及を支えた一方、「なんとなく動いてしまう」ため構造の乱れに気づきにくいという副作用もあります。見た目は正しくても木が想定と違えば、CSSのセレクタが当たらない、JavaScriptが要素を見つけられない、といった不具合の原因になります。開発者ツールで見えるのは書いたHTMLではなくこの木(DOM)なので、「ソースと開発者ツールの表示が違う」ときは、パーサの組み替えを疑います。

もうひとつの副作用がセキュリティです。ユーザー入力をエスケープせずにHTMLへ埋め込むと、それがタグとして解釈されて XSS(クロスサイトスクリプティング)の脆弱性になります。パーサはどんな文字列でも律儀に木にするので、「文字列のつもりで埋めたものが、要素として動き出す」のです。「HTMLは文字列であると同時に、ブラウザに解釈されるコードでもある」という二面性は、セキュリティを考える上で常に意識しておきたい点です。

セマンティックなマークアップ

HTMLのタグには意味があります。単に文字を大きくしたいから <h1> を使うのではなく、「文書の最上位見出しだから」使う。ナビゲーションは <nav>、主内容は <main>、記事は <article>、ボタンは <div> にクリックイベントを付けるのではなく <button> を使う——これをセマンティック(意味論的)なマークアップと呼びます。見た目は CSS でどうにでも変えられるので、<div> だけでも同じ画面は作れます。違いが出るのは、画面を見ない読み手のほうです。

ページの骨組み(HTML)headernavmainarticlefooter支援技術・検索エンジンが受け取る意味bannerサイトの見出し帯navigation移動用のリンク群mainここへ一気に跳べるarticle独立した記事の本体contentinfo著作権・問い合わせdiv だけで同じ見た目を作ると、右の列は空になる
同じ見た目でも、セマンティックな要素は「ここが何か」を画面を見ない読み手に運ぶ

スクリーンリーダーの利用者は、banner・navigation・main のようなランドマーク(ページの区画)の一覧から「本文へ跳ぶ」「ナビゲーションへ跳ぶ」といった移動をします。見出しの <h1>〜<h6> も同じで、見出しだけを拾い読みしてページの目次をつかみます。検索エンジンも構造から内容の重要度を推定します。アクセシビリティとSEOの土台は、正しい要素選びにあります。

フォーム——Webがアプリになった仕掛け

<form> と <input> は、閲覧するだけだったWebに「ユーザーからの入力」を持ち込んだ要素です。フォームを送信するとブラウザは入力値を HTTP リクエストとしてサーバへ送ります。ログイン、検索、購入——Webアプリケーションの原型はすべてフォームです。現在はJavaScriptで送信を制御することが多いものの、<label> で入力欄と説明を結び付ける、バリデーション属性(required や type="email")を使う、といった HTML 自体が持つフォーム機能を活かすと、コードが簡潔になるうえ、スマートフォンでは入力に合ったキーボードが出るなどの恩恵も無償で受けられます。

フレームワーク時代のHTML

React や Vue などのフレームワークを使う開発では、HTMLを直接書く機会は減ったように見えます。しかし SPA はJavaScriptでDOM(=HTMLの木)を組み立てており、SSR や SSG は「最初のHTMLをサーバ側で生成して速く届ける」技術です。JSX で <div onClick> と書けば、出来上がるのはやはり意味を持たない <div> です。モダンフロントエンドの技術群は、いかに良いHTMLを・いつ・どこで生成するかという問いへの答え方の違いであり、HTMLの理解はその出発点になります。

試問

左に HTML を打つと、右にブラウザ標準の DOMParser が組み立てた本物の DOM の木が出ます。書いた入れ子と違う部分(補われた要素・組み替えられた要素・複製された要素)には印が付きます。いまは、段落 <p> の中に箱 <div> を入れた HTML が書かれています。

✦ 命題挑戦中

「説明文」と、要素で包んだ「箱」を、パーサに組み替えられずに1つの要素の中へ収めよ

  • パーサによる組み替え・複製が 0
  • 「説明文」と「箱」が、body 直下ではない同じ要素の中にある
  • 「箱」は、説明文とは別の要素で包まれている
⚡ 体験: 段落の中の箱を、組み替えられない形に直す

HTML(ただの文字列)

DOM(ブラウザで開くと、ここで本物のパーサが動く)

document<!DOCTYPE html><html>補われた<head>補われた<title>"星図"<body>補われた<h1>"知星図"<p>"星を"<b>"つなぐ"
ノード9補われた3組み替え0複製0空白のテキスト3
パーサが補った・複製した書いたときと親が変わったテキストノード

左の HTML を書き換えるか、ひな形を選んでください。右の木は、ブラウザ標準の DOMParser が実際に組み立てたものです。