seo/single-h1 · 見出し階層
<h1> は 1 ページにつき 1 つだけにしましょう。
重大度: warning(<h1> なし)/ info(<h1> が複数)
チェック内容
<h1> が 0 個(主見出しなし、warning)、または 2 個以上(info)のページを検出します。ちょうど 1 個で合格です。ページのレイアウトチェーンにある見出しもそのルートの集計に含めるため、+layout.svelte の <h1> もカウントされます。
グローバルな重大度上書き(rules: { 'seo/single-h1': <severity> })は両方のケースに一律で適用されます。設定はルール ID 単位のキーであり、どちらのケースで検出されたかは区別しないため、上書きすると分割は 1 つの重大度に均されます。
なぜ重要か
<h1> はページの主トピックを表す見出しです。<h1> が 0 個だとページに主見出しがなくなります。シグナルが本当に欠けている状態なので warning です。一方、単一の明確な <h1> はページのトピックを示す慣例的なシグナルですが、複数の <h1> は現代の見出しアルゴリズムでも許容されています。複数あることでランキングにペナルティが科されるという公式情報源はないため、こちらはスタイル上の指摘(info)にとどめ、欠陥としては扱いません。
修正方法
<h1>ページ唯一の、内容を表す説明的なメインの見出し</h1>
<h2>サブセクション</h2>
<h2>別のサブセクション</h2>
モードによる違い
両モードとも見出しを収集しますが、収集元が異なるため結果が食い違うことがあります。
- ソース解析(CLI、ダッシュボードの静的ベースライン)はルートの
.svelteテンプレートを走査します。インポートしたローカルコンポーネントが描画する見出しも(head 解決と同じ、深さ制限付きの走査で再帰的に)追跡するため、<h1>を$libコンポーネントに切り出しても検出されます。ただし{#if false}のようなレンダリングされない分岐の中にある見出しも数えてしまう一方、node_modules由来のコンポーネント・動的に選ばれるコンポーネント・実際にどの条件分岐が描画されるかは見えないため、解決できないコンポーネント内の見出しは依然として偽の「<h1>が見つかりません」を招くことがあり、条件付きで描画される複数の見出しはinfoレベルの過剰カウントを招くことがあります。 - レンダリング解析(Vite プラグインのビルド、ダッシュボードで訪問したルート)はレンダリング済みの HTML を読みます。そのため、コンポーネントが描画したすべての見出しを認識し、実際にレンダリングされた分岐だけを数えます。
両者が食い違う場合は、レンダリング結果(@svelte-vitals/vite)を信頼してください。ブラウザに配信される内容を反映しているのはそちらです。
無効化
既存の検出は suppressions ファイルに記録して抑制できます(npx svelte-vitals --update-suppressions)。overrides でルートやパス単位に絞るか、ルールごと無効化するには、次のように設定します。
export default {
rules: {
'seo/single-h1': 'off'
}
};