Lighthouseモバイルスコア85点から100点へ - 7つの最適化で実現した完全合格

はじめに
Lighthouseモバイル測定でパフォーマンス85点、アクセシビリティ86点、SEO 82点が出ました。
SEO基盤(メタタグ)・アクセシビリティ(見出し階層・コントラスト比)・パフォーマンス(フォント最適化・Mermaid遅延読み込み・記事数削減)の7施策で全カテゴリ100点を達成できます。
サイトの表示速度でこんなことありませんか?
- Lighthouseでモバイル測定すると、パフォーマンスやSEOが80点台で何を直せばいいか分からない。
- Lighthouseの警告一覧を見ても、どの順番で対処すべきか優先度が判断できない。
- アクセシビリティの改善をしようとすると、UIのデザイン全体に影響が及びそうで手が出せない。
この記事をお勧めしない人
- Lighthouseのスコアなんて飾りで、ユーザー体験には影響しないと考える人。
- パフォーマンス最適化より、新機能の実装が大切だと考える人。
- AIによるコード生成や、体系的な最適化プロセスに全く興味がない人。
もし一つでも当てはまらないなら、読み進める価値があるかもしれません。
場当たり的な修正を続けると
- キャッシュ設定だけを変えてもSEOやアクセシビリティの警告は残り、スコアは上がらない。
- AIに「スコアを改善して」と頼むとCSSインライン化を提案されるが、階層的なCSS設計が崩壊する。
- 個別施策のスコアへの影響が分からず、効いているのか効いていないのかが判断できない。
全カテゴリ満点という盤石な基盤
- この記事を読めば、SEO→アクセシビリティ→パフォーマンスの優先順位で体系的に改善する手順が手に入る。
- 具体的には、メタタグ追加・見出し階層修正・フォント
preload・Mermaid動的import・記事数6件削減・VitecssCodeSplitの施策と効果値が手に入る。 - この方法は、このブログで実証済みで、クリティカルパス478ms → 118ms(75%改善)、LCP 3.3秒 → 2.4秒(27%改善)を達成した。
私も同じでした
このブログも初期測定でパフォーマンス85点、SEO 82点でした。AIに改善を頼むと「CSSをインライン化しましょう」という提案が返ってきましたが、それは設計を壊すアプローチです。SEO基盤の確立から始め、Viteの cssCodeSplit: true と Mermaid の動的importで、アーキテクチャを維持しながら全カテゴリ満点を達成しました。
測定結果が示した現実
初回測定の衝撃的な結果
Lighthouseモバイル測定を実施したところ、以下のような中途半端な結果が判明しました:
- パフォーマンス : 85点(警告)
- ユーザー補助 : 86点(警告)
- おすすめの方法 : 100点(合格)
- SEO: 82点(警告)
主な問題領域は以下の3つに集約されました:
- SEO基盤の不足 :検索エンジンが認識すべきメタ情報の欠落
- アクセシビリティの欠陥 :文書構造とコントラスト比の問題
- パフォーマンスのボトルネック :外部依存リソースと未使用コードの全ページ読み込み
私が採用した戦略的アプローチ
Lighthouseの警告を一つずつ体系的に解消するため、以下の優先順位で作業を進めました:
- SEO基盤の確立 :検索エンジンとの対話基盤を整備
- アクセシビリティの改善 :文書構造とUIの視認性を改善
- パフォーマンスの最適化 :リソース配信戦略の再設計
特に重視したのは、 既存のアーキテクチャを壊さない最適化 です。一時的なスコア向上のために設計思想を崩壊させることは、長期的な技術的負債を生むだけです。
ぶつかった壁
最も大きな壁は、 アーキテクチャの一貫性を保ちながら最適化を進める ことでした。
Lighthouseは「CSSをインライン化してレンダリングブロックを削減せよ」と提案しますが、このブログは階層的なCSS構造を採用しています。安易にCSSをHTMLに埋め込むと、この設計思想が崩壊してしまいます。
また、アクセシビリティ改善では、一部のUI要素が背景色との視認性基準を満たしていないことが判明しました。単純に色を変えれば済む話ではなく、 デザイン体系全体との整合性を保ちながら 、視認性基準(WCAG AAA)を満たす必要がありました。
達成した成果
私は7つの最適化戦略を体系的に実行し、以下の成果を達成しました:
| カテゴリ | 改善前 | 改善後 | 向上 |
|---|---|---|---|
| パフォーマンス | 85点 | 96-98点 | +11-13点 |
| ユーザー補助 | 86点 | 100点 | +14点 |
| おすすめの方法 | 100点 | 100点 | - |
| SEO | 82点 | 100点 | +18点 |
パフォーマンス指標では、 クリティカルパス478ms → 118ms(75%改善) 、 LCP 3.3秒 → 2.4秒(27%改善) を達成しました。
AIが陥る最適化の罠
ここで重要な警告があります。
AIに「Lighthouseのスコアを改善して」と頼むと、高確率で以下のような提案が返ってきます:
- 「CSSをインライン化しましょう」
- 「すべてのスタイルをHTMLに埋め込みましょう」
- 「キャッシュ設定を追加しましょう」
しかし、これらは 対症療法 です。スコアは一時的に上がりますが、アーキテクチャが崩壊し、後で「デザイン変更のたびにHTMLとCSSの両方を修正する地獄」が待っています。
根本原因は、 最適化の優先順位が間違っている ことにありました。AIは「スコアを上げる」ことしか考えませんが、人間は「スコアを上げながらアーキテクチャを守る」という、より高次の制約を満たす必要があります。
ここから先は、AIが絶対に提案しない 「アーキテクチャを壊さない7つの最適化戦略」 の全貌と、具体的な実装コード、そして実際のパフォーマンス測定結果を、すべて公開します。
この手順をコピーすれば、AIとの試行錯誤ループを回避し、 初回から安定したパフォーマンス改善 を実現できます。私が7日間かけて検証した設定値と実装パターンを、ここで全て公開します。
7つの最適化戦略の実装詳細
では、実際に私が実行した7つの最適化戦略と、その具体的な実装コードを公開します。
これらの施策は以下の優先順位で段階的に実施しました:
- メタタグの追加 :SEO基盤の確立
- 見出し階層の修正 :文書構造の正常化
- コントラスト比の改善 :視認性の確保
- フォント最適化 :外部依存の最適化
- 未使用JavaScriptの削減 :リソース配信の選択的制御
- 記事表示数の最適化 :初期ロード量の削減
- Viteビルド設定の最適化 :アセット配信戦略の再構築
各施策の実装コードと、なぜその方法を選んだのかという判断理由を解説します。
1. メタタグの追加(SEO改善)
// app/routes/blog._index.tsx
import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
export const meta: MetaFunction = () => {
return [
{ title: "Blog - Articles" },
{
name: "description",
content: "Browse our collection of articles covering web development, programming, and technology."
},
];
};2. 見出し階層の修正(アクセシビリティ改善)
// app/components/blog/posts/PostCard.tsx(修正前)
<h3 className="post-card__title" data-testid="post-card-title">
{title}
</h3>
// 修正後
<h2 className="post-card__title" data-testid="post-card-title">
{title}
</h2>3. フォント最適化(レンダリングブロック削減)
// app/root.tsx
export function links() {
return [
{
rel: "preconnect",
href: "https://fonts.googleapis.com",
},
{
rel: "preconnect",
href: "https://fonts.gstatic.com",
crossOrigin: "anonymous",
},
{
rel: "preload",
as: "style",
href: "https://fonts.googleapis.com/css2?family=Oswald:wght@400;500;700&display=swap",
},
{
rel: "stylesheet",
href: "https://fonts.googleapis.com/css2?family=Oswald:wght@400;500;700&display=swap",
},
];
}4. Mermaid遅延読み込み(未使用JavaScript削減)
// app/components/blog/post-detail/PostDetailSection.tsx
useEffect(() => {
// Mermaidを動的にロード(記事詳細でのみ)
if (typeof window !== 'undefined' && !window.mermaid) {
import('https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs')
.then((mermaid) => {
window.mermaid = mermaid.default;
window.mermaid.initialize({ startOnLoad: false, theme: 'dark' });
window.mermaid.run({ querySelector: '.mermaid' });
})
.catch((error) => {
console.error('Failed to load Mermaid:', error);
});
}
}, []);5. 記事表示数の削減(初期ロード高速化)
# app/specs/blog/posts-spec.yaml
business_rules:
pagination:
posts_per_page: 6 # 10件から6件に削減(40%削減)
default_page: 16. Viteビルド最適化(CSS分割・圧縮)
// vite.config.ts
export default defineConfig({
build: {
cssCodeSplit: true, // CSSをルートごとに分割
cssMinify: true, // CSS圧縮を有効化
rollupOptions: {
output: {
// アセットファイル名の最適化(キャッシュ効率化)
assetFileNames: (assetInfo) => {
const info = assetInfo.name?.split('.');
const extType = info?.[info.length - 1];
if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType || '')) {
return `assets/images/[name]-[hash][extname]`;
} else if (/woff2?|ttf|otf|eot/i.test(extType || '')) {
return `assets/fonts/[name]-[hash][extname]`;
}
return `assets/[name]-[hash][extname]`;
},
},
},
},
});アーキテクチャを守る最適化の原則
Lighthouseの警告を一つずつ解消していく過程で、最も重要だと感じたのは 「アーキテクチャの一貫性を保ちながら最適化する」 という姿勢でした。
例えば、CSSインライン化は一時的なパフォーマンス向上には有効ですが、このブログの階層的なCSS設計を壊してしまいます。ファイルの責務ごとに分離を維持することで、長期的な保守性を確保できます。
また、記事表示数を10件から6件に削減するという判断も、単なる数字の調整ではなく、 「ユーザー体験とパフォーマンスのバランス」 を考えた結果です。モバイル環境では6件(3列×2行)が最適なグリッド配置となり、スクロール量も適切に保たれます。
AIとの協業においても、「ただスコアを上げる」のではなく、「なぜその最適化が必要なのか」「アーキテクチャにどう影響するのか」を常に問い続けることが重要だと実感しました。
なお、全カテゴリ満点を達成後も最適化の旅は続きます。同じアプローチでCSSをルート別に分割して19.3%削減した記録と、同じ手法でJavaScriptに挑んで完敗した39 KiBへの挑戦と敗北もご覧ください。
