セマンティック HTML
a11y の 9 割はここで決まる。適切なタグを使うと、role / name / state / value がブラウザによって自動で組み立てられる。
逆に div と span だけで作ると、それを ARIA で全部埋め直すことになる。
ドキュメントの基本
<html lang> は必須
スクリーンリーダの読み上げ言語、ブラウザの翻訳機能、ハイフネーションなど多くの機能が依存する。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>ページの目的を表す簡潔なタイトル</title>
</head>
...
</html>
ページ内に別言語の塊があるならそこに lang を:
<p>以下は英語の引用です:
<span lang="en">The quick brown fox.</span>
</p>
<title> はページの目的を簡潔に
- 各ページでユニークに。
- 「目的 — サイト名」の順で並べると一覧性がいい(タブを多く開く時に有効)。
- タイトルが「ページの内容」を表していないとスクリーンリーダ利用者は何のページか分からない。
ランドマーク要素
ページの大きな構造を示すタグ。スクリーンリーダ利用者はランドマーク間をジャンプして目的の領域に素早く移動する。
| 要素 | 役割 | 暗黙の role |
|---|---|---|
<header> | ページ全体のヘッダ(最上位の場合) | banner |
<nav> | 主要なナビゲーション | navigation |
<main> | そのページの主要コンテンツ | main |
<aside> | 本文を補足する内容 | complementary |
<footer> | ページ全体のフッタ(最上位の場合) | contentinfo |
<section> + 見出し | 章・節(見出しがあると region になる) | region(見出し付きの場合) |
<article> | 独立して再配布可能な単位 | article |
<form> + ラベル | フォーム(aria-label/labelledby が必要) | form |
<body>
<header>
<a href="/" aria-label="サイトトップへ">ロゴ</a>
<nav aria-label="グローバル">
<ul>
<li><a href="/about">About</a></li>
<li><a href="/blog">Blog</a></li>
</ul>
</nav>
</header>
<main>
<h1>ページタイトル</h1>
...
</main>
<aside aria-label="関連リンク">
...
</aside>
<footer>
<small>© 2026 ...</small>
</footer>
</body>
同じランドマークが複数あるとき
ページ内に <nav> が複数あるなら、それぞれに aria-label を付けて識別する。
スクリーンリーダのランドマーク一覧で「ナビゲーション、ナビゲーション、ナビゲーション」では区別できない。
<nav aria-label="グローバル">...</nav>
<nav aria-label="目次">...</nav>
<nav aria-label="パンくず">...</nav>
見出し階層
h1 ~ h6 は見た目の大きさではなく論理的な階層。
スクリーンリーダ利用者は見出しジャンプでページの構造を把握する。
- 1ページに
h1は1つ(ページタイトル)が分かりやすい。 - レベルを飛ばさない(
h2の下にh4はNG)。 - 大きさが欲しいだけなら
h2に CSS を当てる。見た目でh1を選ばない。
<h1>React の基礎</h1>
<h2>コンポーネント</h2>
<h3>props</h3>
<h3>state</h3>
<h2>フック</h2>
<h3>useState</h3>
ボタンとリンクの使い分け
最頻出の混同。遷移するなら <a>、動作を起こすなら <button>。
<a href> | <button> | |
|---|---|---|
| キーボード | Enter で発火 | Enter / Space で発火 |
| 右クリックメニュー | 「新しいタブで開く」等が出る | 出ない |
| URL を持つ | はい | いいえ |
| 用途 | 場所を移動する | その場で何かを起こす(送信、開閉、削除) |
<!-- BAD: div でボタン -->
<div class="btn" onclick="submit()">送信</div>
<!-- BAD: ハッシュリンクをボタン代わりに -->
<a href="#" onclick="event.preventDefault(); openModal()">開く</a>
<!-- GOOD -->
<button type="button" onclick="openModal()">開く</button>
<button type="..."> を明示
フォームの中の <button> は暗黙で type="submit"。
意図せず submit が走るのを避けるため、常に type を書く。
<button type="submit">送信</button>
<button type="button">キャンセル</button>
<button type="reset">リセット</button>
リスト
並列の項目はリスト要素で。スクリーンリーダは「3項目のリスト」のように個数を読み上げる。
<ul>— 順序のないリスト<ol>— 順序のあるリスト<dl>— 定義リスト(<dt>+<dd>)
ナビゲーションは <ul> でリスト化するのが定番。
要素数が伝わって便利。
テーブル
本物のテーブルデータには <table> を使う。レイアウトに使わない。
<table>
<caption>月別売上</caption>
<thead>
<tr>
<th scope="col">月</th>
<th scope="col">売上</th>
<th scope="col">前年比</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1月</th>
<td>100,000</td>
<td>+10%</td>
</tr>
</tbody>
</table>
<caption>でテーブルの目的を示す。- 列ヘッダは
<th scope="col">、行ヘッダは<th scope="row">。 <thead>/<tbody>/<tfoot>で構造化。
強調・引用
| タグ | 意味 |
|---|---|
<strong> | 強い重要性。スクリーンリーダで強調されることがある。 |
<em> | 言語的な強調(イントネーションの変化)。 |
<b> | 意味を伴わない太字(製品名・キーワード)。 |
<i> | 意味を伴わない斜体(学名・他言語)。 |
<mark> | マーカーで引いた感じ。検索結果のハイライトに。 |
<q> | インラインの引用。 |
<blockquote cite="..."> | ブロック引用。cite で出典 URL。 |
<cite> | 作品名の参照。 |
<abbr title="..."> | 略語。title で展開した形。 |
コンテンツ系
<dialog>
モーダル/非モーダルのダイアログをネイティブで提供。showModal() で開くと
フォーカスのトラップやバックドロップ、Esc キーでの閉じ込みも自動で動く。
<dialog id="confirm">
<form method="dialog">
<p>この操作を実行しますか?</p>
<button value="cancel">キャンセル</button>
<button value="ok">OK</button>
</form>
</dialog>
<script>
document.getElementById("confirm").showModal()
</script>
<details> / <summary>
ネイティブの折りたたみ。アコーディオンを自分で実装する前にこれで足りないか考える。
<details>
<summary>詳細を見る</summary>
<p>隠れていたコンテンツ</p>
</details>
<progress> / <meter>
<progress max value>— タスクの進捗(時間で増える)<meter min max value>— 既知の範囲内の量(バッテリ残量、得点)
<time datetime>
日時は機械可読な形で。datetime 属性で正規化。
<time datetime="2026-05-10">2026年5月10日</time>
避けるべきアンチパターン
<div>でボタン →<button><a href="#">でクリックハンドラ →<button><span>連打のリスト →<ul>- 「お知らせ」を
<div>だけ →role="alert"やaria-live - レイアウトで
<table>→ CSS Grid / Flexbox - 見出しを
<p class="title">→<h2>等 - 装飾だけの画像で
altを書く →alt="" <br>連打で空白 → CSS で margin
そのコンテンツが意味的に何かを考える。
- 場所を移動する→<a>
- 動作する→<button>
- 構造を表す→<header> / <nav> / <main> / <article> / <section>
- 並列項目→<ul>
- データの表→<table>
意味の無い「何か」を入れたい時にだけ <div> / <span>。