semantic-html-and-seo について
セマンティックでアクセシブルなHTMLと検索されやすいページの実装を支援する開発スキルです。メタデータ、構造化データ、プログレッシブエンハンスメント、SPAのアクセシビリティとSEOを扱います。
主な機能
- 01セマンティックなHTML構造
- 02画像の代替テキスト指針
- 03SEOメタデータと構造化データ
- 04プログレッシブエンハンスメントの実践
- 05SPAのアクセシビリティとSEOの確認
活用シーン
- 01見出しと文書構造のレビュー
- 02メタデータと共有カードの準備
- 03SPAのアクセシビリティと検索対応の改善
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dembrandt/ dembrandt-skills --skill semantic-html-and-seoインストール後、Claude Code で/semantic-html-and-seoを入力して読み込まれたか確認します。
詳細
セマンティック HTML と SEO
優れた HTML は単なるマークアップではありません。コンテンツ、検索エンジン、支援技術、ブラウザーの間の契約です。セマンティック HTML、適切なメタデータ、プログレッシブエンハンスメントにより、UI は標準で堅牢かつ見つけやすく、アクセシブルになります。
セマンティック HTML5
見た目だけでなく、コンテンツの意味を表す要素を使用してください。
ドキュメント構造
<header>
<nav>
<main>
<article>
<section>
<aside>
<footer>
見出し
1 ページにつき <h1> は 1 つにします。ページの主題を表す見出しです。見出しでアウトラインを構成します。レベルを飛ばさないでください(h1 → h3 のように、h2 を飛ばすのは避けてください)。
<h1>Product name</h1>
<h2>Features</h2>
<h3>Feature detail</h3>
<h2>Pricing</h2>
インタラクティブ要素
<button>
<a href>
<input>
<select>
<details> / <summary>
完全な ARIA 属性を付けずに <div> や <span> をインタラクティブ要素として使用しないでください。また、属性を付ける場合でも、ネイティブ要素を優先してください。
画像と代替テキスト
すべての <img> に alt 属性が必要です。設定する内容はコンテキストによって異なります。
| 画像の種類 | 代替テキスト |
|---|---|
| 情報を伝える画像(製品写真、グラフ) | 内容を説明します:alt="赤い革張りの3人掛けソファ" |
| 機能を持つ画像(アイコンボタン、ロゴリンク) | 機能を説明します:alt="ホームページに移動" |
| 装飾画像 | 空にします:alt="" — スクリーンリーダーは読み飛ばします |
| 複雑な画像(グラフ、図) | 短い代替テキストに加え、近くに長い説明を置くか、<figcaption> に記載します |
<img src="sofa.jpg" alt="Red leather sofa, three-seater">
<img src="divider.svg" alt="">
<figure>
<img src="chart.png" alt="Bar chart showing revenue growth Q1–Q4 2025">
<figcaption>Revenue grew 42% year-on-year in Q4 2025.</figcaption>
</figure>
SEO の基本
タイトルと説明
<title>Product Name — Short descriptor | Brand</title>
<meta name="description" content="One or two sentences. What this page is, who it is for, what they will find.">
- タイトル:50~60 文字にします。最も重要なキーワードを先頭に置きます。
- 説明:120~160 文字にします。検索結果に表示されるため、アルゴリズムではなく人に向けて書いてください。
正規 URL
<link rel="canonical" href="https://example.com/the-definitive-url">
同じページに複数の URL からアクセスできる場合に、重複コンテンツによるペナルティを防ぎます。
Open Graph(ソーシャル共有)
<meta property="og:title" content="Page title">
<meta property="og:description" content="Page description">
<meta property="og:image" content="https://example.com/og-image.jpg">
<meta property="og:url" content="https://example.com/page">
<meta property="og:type" content="website">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Page title">
<meta name="twitter:image" content="https://example.com/og-image.jpg">
OG 画像:1200×630px。URL が Slack、LinkedIn、Twitter、iMessage で共有されたときに表示されます。
カードの見出しには、記事の知見ではなく、読者が使う言葉を選びます。 フィードには文脈がないため、記事を読まないと意味が通じない一文は、スクロール中の見知らぬ人には意味不明に映ります。読者がすでに探している、わかりやすい約束を、そのプラットフォームで使われている言葉でカードに載せ、気の利いた一文はページ本文に残してください。
色合いではなく、モードに合わせてプラットフォームごとにカードを調整します。 明るいフィードでは暗いカードが広告バナーのように見えます。そのプラットフォームの背景に合わせて明るいカードにするのが解決策であり、ネイビーを少し暖色寄りにしたり、青を少し淡くしたりすることではありません。プラットフォームの UI に並ぶと、色相をわずかに変えても気づかれず、無駄な往復作業が増えるだけです。トーンの微調整は、モードを適切にしてから行います。
構造化データ(JSON-LD)
機械可読コンテンツにより、リッチ検索結果を表示できます。
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Product Name",
"description": "Product description",
"image": "https://example.com/product.jpg",
"offers": {
"@type": "Offer",
"price": "49.00",
"priceCurrency": "EUR"
}
}
</script>
一般的なタイプ:Product、Article、BreadcrumbList、FAQPage、Organization、SiteLinksSearchBox。
プログレッシブエンハンスメント
レイヤーを重ねて構築します。コアとなるコンテンツと機能は、JavaScript なしで動作しなければなりません。CSS で拡張し、さらに JS で拡張します。
Layer 1: HTML — content is readable, links work, forms submit
Layer 2: CSS — layout, typography, visual design
Layer 3: JS — interactivity, animations, dynamic content
実際には:
- フォームは JS なしでネイティブの
<form action>を使って送信できる必要があります。JS で送信を捕捉し、fetch で機能を拡張できます - ナビゲーションリンクには実際の
<a href>を使用する必要があります。JS でトランジションを追加できます - コンテンツは HTML 内に含める必要があります。JS で遅延読み込みやパーソナライズを追加できます
- 画像には
srcが必要です。JS でloading="lazy"を使った遅延読み込みを追加できます(現在はネイティブで対応しています)
SPA に関する考慮事項
シングルページアプリケーションは、SEO とアクセシビリティが依存するブラウザーの既定の動作を損ないます。明示的に対処してください。
サーバーサイドレンダリングまたは静的生成
クライアント側でレンダリングされた HTML は、検索エンジンに確実にインデックス登録されるとは限りません。見つけてもらう必要のあるコンテンツには、SSR(Next.js、Nuxt、SvelteKit)または静的生成を使用してください。
タイトルとメタデータの更新
ルートが変わるたびに document.title とメタタグを更新してください。フレームワークの <Head> コンポーネントまたは同等のものを使用してください。
フォーカス管理
ルートが変わったら、新しいページの <h1> または <main> にフォーカスを移動します。スクリーンリーダーは SPA のナビゲーションを自動的には検知しません。
// After route change
document.querySelector('h1')?.focus();
スクロール位置の復元
ナビゲーション時にスクロール位置を先頭に戻すか、戻るナビゲーション時に保存した位置へ戻します。SPA では、ブラウザーの既定のスクロール位置復元が無効になっています。
History API
pushState / replaceState を使用して、戻る/進むナビゲーションやブックマークが正しく機能するようにします。
デバイスの機能とユーザーコンテキスト
デザインとコードは、デバイスとユーザーが実際にできることに合わせて調整する必要があります。
クライアント側ストレージをパーソナライズに活用する
localStorage、sessionStorage、その他のブラウザー機能(Cookie、IndexedDB、メディアや権限のクエリ)は、エクスペリエンスを調整するための適切な手段です。前回の表示モード、選択したロケール、非表示にしたバナー、作成途中の下書き、再訪ユーザーのコンテキストなどを保存できます。
ガードレール:
- 推測ではなく、実際の理解に基づいてパーソナライズします。 何を安全に保存して事前入力するかは、通常、ユーザーテストで確認する必要があります。保存された状態に基づく誤った想定は、何も設定しない場合よりも悪い結果を招きます。
- 範囲と同意。 1 回のセッションでは
sessionStorage、セッションをまたぐ場合はlocalStorageを使います。機密情報はクライアント側に保存せず、同意を尊重してください。 - 2~3 年ごとに再検証します。 ニーズは変化します。提供開始時には適切だったパーソナライズも、やがて使いにくさにつながることがあります。できれば新たにテストを実施して見直してください。
入力方式の検出
@media (hover: hover) {
/* hover states — mouse or trackpad */
.btn:hover { background: var(--color-primary-hover); }
}
@media (hover: none) {
/* touch device — no hover, larger targets */
.btn { min-height: 44px; }
}
ポインターの精度
@media (pointer: coarse) {
/* fat-finger touch — increase target sizes */
.interactive { min-height: 44px; min-width: 44px; }
}
@media (pointer: fine) {
/* mouse — precise, can use smaller targets */
}
ポインターの精度は、ターゲットのサイズだけでなく、デフォルトの動作も選択できます。同じクエリは JavaScript の matchMedia('(pointer: fine)') で確認できますが、操作モデルが異なる場合は、各イベントの pointerType を使ってください。たとえば、クリックでは切り替え、マウスではポインターによるパン、タッチではピンチやダブルタップといった違いです。ハイブリッドデバイスでは推測が外れるため、ビューポートの幅から入力方式を推定しないでください。画像のズームについては [[modal-and-overlay-patterns]] を参照してください。
ネットワークの状態
<img src="product.jpg" loading="lazy" alt="...">
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="...">
</picture>
ユーザー設定
@media (prefers-reduced-motion: reduce) { /* disable animations */ }
@media (prefers-color-scheme: dark) { /* dark mode tokens */ }
@media (prefers-contrast: more) { /* increase contrast */ }
@media (forced-colors: active) { /* Windows high contrast mode */ }
レビューチェックリスト
- 1 ページにつき
<h1>が 1 つあり、見出しが論理的な階層を構成している -
<main>、<nav>、<header>、<footer>、<article>、<section>などのセマンティック要素を使用している - すべての
<img>に意味のあるaltが設定されている。装飾画像の場合はalt=""を設定している - ページごとに固有の
<title>があり、50~60 文字で、キーワードが先頭にある -
<meta name="description">が設定されており、120~160 文字である - 共有可能なすべてのページに Open Graph タグが設定されている
- 複数の URL からアクセスできるページに
<link rel="canonical">が設定されている - 製品、記事、FAQ のページに構造化データ(JSON-LD)が設定されている
- JavaScript がなくてもフォームが動作する
- SPA がルート変更時に
document.titleとメタタグを更新する - SPA がルート変更時にフォーカスを移動する
- ホバー状態が
@media (hover: hover)の範囲内に設定されている -
@media (pointer: coarse)でタッチターゲットが 44px 以上である - ファーストビューより下の画像に
loading="lazy"を設定している -
prefers-reduced-motionを尊重している