技術・開発
Web パフォーマンス最適化の実践 - サイトを爆速にする方法
「サイトの読み込みが遅い」「Lighthouseのスコアが低い」「ユーザーの離脱率が高い」——Webサイトのパフォーマンスは、ユーザー体験を左右する重要な要素です。Googleの調査によると、ページ読み込みが3秒以上かかると、53%のユーザーが離脱するとされています。
この記事では、MechaToraの15個のツールでLighthouseスコア90点以上を達成した経験から、実践的なパフォーマンス最適化手法を解説します。画像圧縮、遅延読み込み、CSS/JS最適化など、今すぐ使える技術をお伝えします。
パフォーマンスが重要な理由
3つの影響
- ユーザー体験:読み込みが遅いとイライラして離脱
- SEO:Googleの検索順位に影響(Core Web Vitals)
- コンバージョン:1秒遅延で売上7%減(Amazon調査)
MechaToraの改善実績
| 指標 | 最適化前 | 最適化後 |
|---|---|---|
| Lighthouseスコア | 72点 | 94点 |
| 読み込み時間 | 4.2秒 | 1.8秒 |
| ページサイズ | 3.5MB | 850KB |
Lighthouseでの測定
Lighthouseの使い方
- Chrome DevTools を開く(F12)
- Lighthouse タブを選択
- 「Analyze page load」をクリック
主要な指標
- FCP(First Contentful Paint):最初のコンテンツが表示されるまでの時間
- LCP(Largest Contentful Paint):最大コンテンツが表示されるまでの時間
- TBT(Total Blocking Time):メインスレッドがブロックされた時間
- CLS(Cumulative Layout Shift):レイアウトのずれ
- Speed Index:ページ内容が視覚的に表示される速度
最適化1:画像の最適化
問題:画像が重すぎる
最適化前のMechaToraトップページ:
- 15枚の画像、合計2.8MB
- ページ全体の80%を画像が占める
- 読み込みに3秒以上
解決策1:画像圧縮
無料ツールで圧縮:
- TinyPNG:PNG/JPEGを70〜80%圧縮
- Squoosh:Googleのツール、WebP変換も可能
- ImageOptim:Mac用、ドラッグ&ドロップで圧縮
結果:2.8MB → 680KB(75%削減)
解決策2:次世代フォーマット(WebP)
<!-- 従来のJPEG -->
<img src="app-screenshot.jpg" alt="アプリ画面">
<!-- WebP対応(フォールバック付き) -->
<picture>
<source srcset="app-screenshot.webp" type="image/webp">
<source srcset="app-screenshot.jpg" type="image/jpeg">
<img src="app-screenshot.jpg" alt="アプリ画面">
</picture>
WebPは同じ品質でJPEGより25〜35%小さくなります。
解決策3:遅延読み込み(Lazy Loading)
<!-- loading="lazy" を追加するだけ -->
<img src="large-image.jpg" alt="説明" loading="lazy">
<!-- 画面外の画像は必要になるまで読み込まれない -->
効果:初回読み込み時間が40%短縮
解決策4:レスポンシブ画像
<!-- 画面サイズに応じて適切なサイズの画像を配信 -->
<img
srcset="app-320w.jpg 320w,
app-640w.jpg 640w,
app-1280w.jpg 1280w"
sizes="(max-width: 640px) 100vw,
(max-width: 1280px) 50vw,
33vw"
src="app-640w.jpg"
alt="アプリ画面"
>
最適化2:CSS/JSの最適化
問題:レンダリングブロック
CSS/JSが全て読み込まれるまで、ページが表示されません。
解決策1:クリティカルCSSのインライン化
<!-- 最初に表示される部分のCSSをHTMLに直接記述 -->
<head>
<style>
/* クリティカルCSS(ファーストビューに必要な最小限のスタイル) */
body {
margin: 0;
font-family: sans-serif;
}
.hero {
background: #2563eb;
color: white;
padding: 2rem;
}
</style>
<!-- 残りのCSSは非同期読み込み -->
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
</head>
解決策2:JavaScriptの非同期読み込み
<!-- 悪い例:レンダリングブロック -->
<script src="app.js"></script>
<!-- 良い例1:defer(DOMの後に実行) -->
<script src="app.js" defer></script>
<!-- 良い例2:async(読み込み完了次第実行) -->
<script src="analytics.js" async></script>
使い分け:
- defer:DOM操作が必要なスクリプト
- async:Google Analyticsなど独立したスクリプト
解決策3:CSSの最小化
/* 最適化前(改行、スペース、コメント含む) */
.button {
background-color: #2563eb;
color: white;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
}
/* 最適化後(1行、スペース削除) */
.button{background-color:#2563eb;color:white;padding:.75rem 1.5rem;border-radius:.5rem}
ツール:
最適化3:フォントの最適化
問題:Webフォントが重い
Google Fontsを読み込むと、数百KBのファイルをダウンロードします。
解決策1:font-display: swap
/* システムフォントを先に表示、Webフォント読み込み後に切り替え */
@font-face {
font-family: 'Noto Sans JP';
src: url('NotoSansJP.woff2') format('woff2');
font-display: swap; /* これを追加 */
}
解決策2:必要な文字だけ読み込む
<!-- Google Fonts: 日本語サブセット -->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap&subset=japanese" rel="stylesheet">
解決策3:システムフォントを使う
body {
font-family:
-apple-system, /* macOS, iOS */
BlinkMacSystemFont, /* macOS Chrome */
"Segoe UI", /* Windows */
"Helvetica Neue",
"Hiragino Sans", /* macOS日本語 */
"Hiragino Kaku Gothic ProN", /* macOS日本語 */
"Noto Sans CJK JP", /* Linux日本語 */
"Yu Gothic", /* Windows日本語 */
sans-serif;
}
Webフォント不要で、0バイト!
最適化4:キャッシュの活用
ブラウザキャッシュ
GitHub Pagesは自動的にキャッシュヘッダーを設定してくれます。自前サーバーの場合:
# .htaccess(Apache)
<IfModule mod_expires.c>
ExpiresActive On
# 画像:1年間キャッシュ
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
# CSS/JS:1ヶ月キャッシュ
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
# HTML:1時間キャッシュ
ExpiresByType text/html "access plus 1 hour"
</IfModule>
Service Workerでのキャッシュ
// sw.js
const CACHE_NAME = 'mechatora-v1';
const urlsToCache = [
'/',
'/styles.css',
'/app.js',
'/images/logo.png'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
最適化5:コンテンツ配信の最適化
CDNの活用
Cloudflare(無料)を使うと:
- 世界中のサーバーにコンテンツをキャッシュ
- ユーザーに最も近いサーバーから配信
- 自動的に画像圧縮・最適化
設定方法:
- Cloudflare でアカウント作成
- ドメインを追加
- ネームサーバーを変更
- 自動最適化をON(Speed → Optimization)
プリロード・プリフェッチ
<head>
<!-- 重要なリソースを優先読み込み -->
<link rel="preload" href="styles.css" as="style">
<link rel="preload" href="app.js" as="script">
<!-- 次に見るページを先読み -->
<link rel="prefetch" href="about.html">
</head>
最適化6:HTMLの最適化
DOM要素を減らす
<!-- 悪い例:不必要なdivが多い -->
<div class="container">
<div class="wrapper">
<div class="inner">
<div class="content">
<p>テキスト</p>
</div>
</div>
</div>
</div>
<!-- 良い例:必要最小限 -->
<div class="container">
<p>テキスト</p>
</div>
HTMLの最小化
改行・スペース・コメントを削除:
<!-- 最適化前 -->
<html>
<head>
<title>MechaTora</title>
</head>
<body>
<h1>見出し</h1>
</body>
</html>
<!-- 最適化後 -->
<html><head><title>MechaTora</title></head><body><h1>見出し</h1></body></html>
実践:MechaToraの最適化プロセス
ステップ1:現状把握
# Lighthouseで測定
- Performance: 72点
- 主な問題: 画像が大きい、JSがブロッキング
ステップ2:画像最適化
- 全画像をTinyPNGで圧縮:2.8MB → 680KB
- WebP変換:さらに30%削減
- loading="lazy" 追加
ステップ3:CSS/JS最適化
- deferとasync追加
- クリティカルCSSをインライン化
- 不要なCSS削除(300KB → 80KB)
ステップ4:再測定
# Lighthouse再測定
- Performance: 94点(+22点)
- 読み込み時間: 1.8秒(-2.4秒)
まとめ
優先度の高い最適化
- 画像圧縮:最も効果が大きい
- 遅延読み込み:loading="lazy"を追加するだけ
- JS/CSSの非同期読み込み:defer/async追加
- Webフォント最適化:font-display: swap
チェックリスト
- ✅ 画像を圧縮(TinyPNG、Squoosh)
- ✅ WebP形式に変換
- ✅ loading="lazy" 追加
- ✅ JavaScript に defer 追加
- ✅ CSS を最小化
- ✅ Webフォントに font-display: swap
- ✅ CDN(Cloudflare)を設定
- ✅ Lighthouseで90点以上を目指す
パフォーマンス最適化は、一度やれば終わりではなく、継続的な改善が重要です。MechaToraでは、新しいツールを追加するたびにLighthouseで測定し、90点以上を維持しています。
まずは、画像圧縮とloading="lazy"から始めてみてください!