/aeo-geo-bestpractices — SEO + AEO + GEO + Lighthouse 100 Playbook
あらゆるページやSPAを、有機的な発見(SEO)、回答エンジン(AEO)、生成AI/AIエージェント(GEO)のためのマシンに変え、同時に5つのカテゴリー(パフォーマンス、アクセシビリティ、ベストプラクティス、SEO、エージェンティックブラウジング)すべてでGoogle Lighthouse 13で98〜100(デスクトップとモバイル)を達成するための完全なワークフローです。
パス: <skill> はこの SKILL.md が配置されているフォルダです。
0. 実行前のクイックアラインメント
0.1. スタックを特定し、対応するガイドを読む
このファイルのルールはあらゆるサイトに適用されます。フレームワーク間で異なる点(<head>の場所、公開フォルダ、プリレンダリング方法、画像の最適化とTBT回避方法、プレビューを起動するコマンド)は references/frameworks/ にあります。プロジェクトからスタックを特定し、ステップ1〜5を適用する前にガイドを読んでください:
| プロジェクト内のシグナル | スタック | ガイド |
|---|---|---|
angular.json または @angular/core | Angular | references/frameworks/angular.md |
next.config.* または next | Next.js | references/frameworks/nextjs.md |
nuxt.config.* または nuxt / vite.config.* + vue | Nuxt / Vue + Vite | references/frameworks/vue-nuxt.md |
astro.config.* または astro | Astro | references/frameworks/astro.md |
vite.config.* + react | Vite + React | references/frameworks/vite-react.md |
index.html フレームワークなし | 静的HTML | references/frameworks/html-estatico.md |
スタックがリストにない場合(例:SvelteKit、Remix、Gatsby、WordPress)、このファイルの一般的なルールを適用し、最も近いガイドを参考にしてください。SSR/SSGフレームワークはNext/Nuxtのロジックに従い、SPAはVite + Reactのロジックに従います。
0.2. ユーザーに確認する
コードを変更する前に、以下を確認(またはプロジェクト自体から既に明示されている場合は抽出)してください:
- 本番環境の正規ドメイン(例:
https://meusite.com.br/)。ドメインが未定義の場合は、質問するか、明確なプレースホルダーを使用してユーザーに通知してください。 - FAQの表示 vs. 非表示(AEO/GEOのみ):
- ユーザーがページレイアウトに**よくある質問(FAQ)**セクションを表示したいか(
<details>/<summary>)、それともバックグラウンドでのみ非表示(@graphJSON-LD +llms.txt+<noscript>内)にして視覚的なデザインを変更しないかを尋ねてください。
- ユーザーがページレイアウトに**よくある質問(FAQ)**セクションを表示したいか(
- トレーニングのためのクローリング設定(
robots.txtを作成または変更する場合):- サイトがすでに設定を定義しているか確認してください。明確な選択がない場合は、2つのオプションを提供してください:検索を許可し、OpenAIおよびAnthropicのトレーニングのためのクローリングをブロックする;または、そのトレーニングのためのクローリングも許可する。サイトの他のルールは保持してください。
1. 完全な技術的SEO(index.html、robots.txt、sitemap.xml)
references/templates.md にある既成のテンプレートを参照してください。
<head>内の必須メタタグ:<html lang="ja">(またはプロジェクトの言語)。- 強力な
<title>(50〜65文字)にブランド名/専門家名 + 主な提案を含める。 <meta name="description">(140〜165文字)で何か、誰のためか、何が含まれているかを明確に答える。<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" /><link rel="canonical" href="https://domain.com/" />+<link rel="alternate" hreflang="ja" ... />およびx-default。- 完全なOpen Graph(
og:type、og:locale、og:site_name、og:title、og:description、og:url、og:image、og:image:width、og:image:height、og:image:alt)とTwitter Cards(summary_large_image)。
- 検索エンジンとAIに優しい
public/robots.txt:- ChatGPTとClaudeの検索に表示される可能性を維持するには、
OAI-SearchBotとClaude-SearchBotを許可します。Claude-Userはユーザーのリクエストに応じてページを検索できます。ChatGPT-Userもユーザーによってトリガーされますが、ChatGPTの検索への掲載を制御するものではありません。 GPTBotとClaudeBotは、トレーニングでのコンテンツ使用の可能性について文書化されたボットです。ユーザーがこのクローリングをブロックすることを選択した場合、両方に対してDisallow: /の専用グループを使用し、検索ボットはブロックしないでください。許可することを選択した場合、両方にAllow: /を使用してください。2つのバリアントについては、references/templates.mdを参照してください。Google-Extendedなど、他のプロバイダーのコントロールは個別に扱います。検索ボットへのアクセスを許可すると対象となる可能性が高まりますが、回答での引用や存在が保証されるわけではありません。ボットのリストを更新する際は、OpenAIのガイドラインおよびAnthropicのガイドラインを参照してください。Sitemap: https://domain.com/sitemap.xmlを指すようにします。
- ChatGPTとClaudeの検索に表示される可能性を維持するには、
- リッチな
public/sitemap.xml(画像+動画):- 注目の画像やセールス/プレゼンテーション動画がある場合は、名前空間
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"およびxmlns:video="http://www.google.com/schemas/sitemap-video/1.1"を含めます。
- 注目の画像やセールス/プレゼンテーション動画がある場合は、名前空間
2. AEO — Answer Engine Optimization(注目スニペット、音声、JavaScriptなしクローラー)
回答エンジンには、接続されたエンティティとJavaScriptを実行せずに読み取り可能なセマンティックHTMLが必要です:
Schema.orgJSON-LD内の接続された@graph:- 個別のJSON-LDスクリプトの代わりに、エンティティを
@idで接続した単一の<script type="application/ld+json">を@graphで作成します(モデルはreferences/templates.mdを参照):WebSite(#website)- 公式ソーシャルメディアへの
sameAsを持つPersonまたはOrganization(#person/#org) aboutとmainEntityを持つWebPage(#webpage)offersを持つProduct/SoftwareApplication/Service(#product)- コース/トレーニング/教育ボーナスがある場合の
Course(#course) - VSLまたはプレゼンテーション動画がある場合の
VideoObject(#video) - 検索意図の高い実際の質問4〜6個と、直接的で完全な回答(それぞれ40〜70語)を持つ
FAQPage(#faq)。
- 個別のJSON-LDスクリプトの代わりに、エンティティを
- SPA(React / Vue / Vite)のためのセマンティックフォールバック
<noscript>:- プリレンダリングなしのSPAにのみ適用されます。Next.js、Nuxt、Astro、SSR/プリレンダリング付きAngular、静的HTMLでは、HTMLは既に完全に到着しているため、
<noscript>は不要です(スタックガイドを参照)。 - LLMクローラー(
GPTBot、ClaudeBot、PerplexityBot、OAI-SearchBot)は、多くの場合、生のHTMLのみをフェッチし、JavaScriptバンドルを実行しません。 <div id="root"></div>が空で届くSPAプロジェクトでは、index.htmlに<noscript><main>...</main></noscript>ブロックを追加し、<h1>、オファーの概要、 deliverablesのリスト(<ul><li>)、CTA/チェックアウトへの直接リンクを含めます。- パフォーマンス上の重要事項:
<noscript>を使用してください(createRoot().render()を使用する場合、<div id="root">内の要素は使用しないでください)。SSRなしで#root内にDOMを配置すると、Reactがマウント時にツリー全体をアンマウントして再作成し、LCPを遅らせTBTを発生させます。
- プリレンダリングなしのSPAにのみ適用されます。Next.js、Nuxt、Astro、SSR/プリレンダリング付きAngular、静的HTMLでは、HTMLは既に完全に到着しているため、
3. GEO & Agentic Browsing(Lighthouse 13で100点)
Google Lighthouse 13は、エージェンティックブラウジングカテゴリを導入しました。これは、ページが自律エージェントとLLM(llms-txt および ard-schema)に対して準備ができているかを監査します。
public/llms.txt+<head>へのリンク:- 構造化されたMarkdownで
public/llms.txtを作成します(references/templates.mdを参照)、以下を含めます:# 製品名 / ブランド> 価値提案の一文要約- 明確なセクション:
## 概要、## 含まれるもの、## ボーナス / 条件、## よくある質問(AEO / GEO)、## 公式リンク。
index.htmlの<head>に以下を追加します:<link rel="help" type="text/plain" href="/llms.txt" title="LLMs.txt — AIのための構造化情報" />
- 構造化されたMarkdownで
public/.well-known/ard.json(Agent Resource Discovery v0.91):- SPA(Vite、Next.jsなど)では、
/.well-known/ard.jsonのような存在しないルートは、フォールバックによってindex.html(<!doctype html>)を返し、Lighthouse 13のard-schema監査がJSONパースエラーで失敗します。 - 常に公式ARD v0.91スキーマに従って
public/.well-known/ard.jsonファイルを作成してください(正確なモデルはreferences/templates.mdにあります):ardVersion: "0.91.0"と、identifierがurn:air:<domain>:<type>:<slug>形式のentries、displayName、type: "application/agent-skills+md"、/llms.txtを指すurl、description、representativeQueriesを含める必要があります。
- SPA(Vite、Next.jsなど)では、
4. Google Lighthouse 100/100: パフォーマンス & アクセシビリティ
モバイル(シミュレート4G + 4倍CPUスロットリング)で98〜100、デスクトップで100を達成するには、以下のルールを厳密に適用してください:
4.1. LCP(Largest Contentful Paint < 2.1秒 モバイル)
<head>上部でのプリロード:<link rel="preload" as="image" ... fetchpriority="high">を、数十のOpen GraphメタタグやJSON-LDの前に、<title>のすぐ下(index.htmlの最初の15行以内)に配置します。
- LighthouseモバイルのDPR
1.75xに対するsrcSetとsizesの調整:- Lighthouseモバイルは Moto G Power(幅
412px、devicePixelRatio: 1.75) をエミュレートします。 - 画像に
sizes="(max-width: 767px) 260px, 500px"がある場合、Chromeは260 * 1.75 = 455wを計算します。srcSetでモバイルバージョンが260w(455wより小さい)として宣言されている場合、Chromeはモバイル画像を無視し、重いデスクトップバージョンをダウンロードします! - 黄金律:
srcSetでモバイル画像を、>= ceil(css_mobile_width * 1.8)の幅(例:240px画像には450w、モバイルで全幅の360px画像には680w)で宣言し、WebP(< 30 KB)に圧縮します。
- Lighthouseモバイルは Moto G Power(幅
- 装飾的な背景画像がLCPを「奪う」のを防ぐ:
- Heroセクションに、メインポートレートや
<h1>よりも大きいバウンディングボックスを持つ装飾的な背景写真(opacity: 0.15)がある場合、ChromeはそれをLCP要素と見なします。 - モバイル(
@media (max-width: 767px))では、純粋に装飾的な巨大な背景写真を非表示(display: none)にするか、その寸法を減らして、メイン要素(fetchpriority="high"でプリロード済み)が唯一のLCP候補になるようにします。
- Heroセクションに、メインポートレートや
- SPAで重要なJS/CSSと競合するフォントをプリロードしない:
@font-faceでfont-display: swapを使用し、ブラウザに二次フォントの前にCSSと初期JSバンドルのダウンロードを優先させます。
4.2. TBTゼロ(0ms 合計ブロック時間)
- 継続的なJSアニメーションをCSSコンポジター +
IntersectionObserverに置き換える:- 初期バンドル内の完全なアニメーションライブラリは、
50〜150 KBのJSを追加し、ハイドレーション時にメインスレッドをブロックします。 - スクロール表示には、ネイティブの
IntersectionObserverを使用して.is-visibleクラスを切り替え、GPU加速(translate3d)によるtransition: opacity, transformを適用します。 - パーティクルや継続的な回転には、
transform: translate3d(...)/rotate(...)とwill-change: transformを使用したCSS@keyframesを使用します。
- 初期バンドル内の完全なアニメーションライブラリは、
- ロード時のSVGフィルター(
<feTurbulence>、drop-shadow)とSMIL<animate>に注意:- 固定サイズなしで全画面に
<feTurbulence>を使用しないでください(CPUで数百万ピクセルのパーリンノイズを再計算し、300ms+の長時間タスクを生成します)。代わりに、軽量なCSSradial-gradientを優先します。 - SVG子要素が初期ロード時に毎フレームジオメトリの変更を受ける親要素に
filter: drop-shadow(...)を組み合わせないでください。<animate attributeName="d">を介した<path>のモーフィングがある場合、ユーザーの最初のインタラクション(pointermove、touchstart、wheel)後、または初期ロード後(setTimeoutで8000ms)までモーフィングを有効にせず、ロード中はGPU上でのCSS回転のみを維持します。
- 固定サイズなしで全画面に
- スムーススクロール(
Lenis)のコード分割:Lenisを、最初のwheel、touchstart、またはkeydownイベント({ passive: true, once: true })でのみ動的にロードします(await import("lenis"))。これにより、初期ロード時は0 KBかつ0msのCPUになります。
- タイマー(
setInterval/ 緊急カウンター)をリーフコンポーネントに分離する:- ルートコンポーネント
<App />にuseCountdownフック(setInterval1秒)を決して配置しないでください。これにより、Lighthouseテスト中、Reactが毎秒ページ全体を再レンダリングするよう強制されます。クロックの状態を、数字のみをレンダリングする小さな<CountdownClock />コンポーネントに分離します。
- ルートコンポーネント
4.3. アクセシビリティ スコア100(WCAG AA)
- 色のコントラスト(
color-contrast):- 暗い背景(
#10100f/#171512)上の小さなテキストは、コントラスト比>= 4.5:1が必要です。二次テキストには薄い色合い(#c4beb4、#d6c5b2)を、暗い背景上のハイライトには明るいオレンジ色(#ff9452、#ffa36b)を使用します。 - 鮮やかなオレンジ色の背景(
#ff772f)を持つボタンは、最大のコントラストを得るために暗いテキスト(#140c06)を使用する必要があります。
- 暗い背景(
- 表示テキストとアクセシブルな名前の一貫性(
label-content-name-mismatch):- リンク/ボタンに、その中に含まれる表示テキストと正確に一致しない
aria-labelを決して配置しないでください(例:ロゴがCF ZANELLA.と表示されている場合、aria-label="ホーム"を配置しないでください)。
- リンク/ボタンに、その中に含まれる表示テキストと正確に一致しない
- セマンティクスとキーボード:
<a class="skip-link" href="#conteudo">コンテンツにスキップ</a>を<body>の最初のフォーカス可能要素として含めます。- 厳密な見出し階層(
h1->h2->h3)、すべての<section>にaria-labelledby、状態セレクターにaria-pressedを使用します。
5. Google Lighthouse による自動検証
スキルの自動化スクリプトを実行して、変更を常に検証してください:
# ローカルプロジェクト: スタックを検出し、`npm run build`(存在する場合)を実行し、ポート4173でプレビューを起動します
node <skill>/scripts/run-lighthouse.mjs
# ビルドをスキップ(ビルド出力が既に最新の場合)
node <skill>/scripts/run-lighthouse.mjs --skip-build
注意: このワークフローは、
references/templates.mdの最新テンプレートと、references/frameworks/の各フレームワークガイドに依存しています。ワークフローの一部として常にこれらのファイルを読み、適用前にユーザーと設定を確認してください。