Webパフォーマンス最適化の実践テクニック
なぜパフォーマンスが重要か
Webサイトの読み込み速度は、ユーザー体験、SEO、コンバージョン率に直接影響します。Googleの調査によると、ページの読み込み時間が1秒から3秒に増えると、直帰率が32%増加するとされています。
Core Web Vitalsの理解
Googleが重視する3つの指標:
LCP (Largest Contentful Paint)
最大のコンテンツが表示されるまでの時間
- 目標: 2.5秒以内
FID (First Input Delay)
ユーザーの最初の操作に応答するまでの時間
- 目標: 100ms以内
CLS (Cumulative Layout Shift)
視覚的な安定性
- 目標: 0.1以下
画像の最適化
1. 適切なフォーマットの選択
<!-- WebP形式を優先、フォールバックも用意 -->
<picture>
<source srcset="image.webp" type="image/webp">
<source srcset="image.jpg" type="image/jpeg">
<img src="image.jpg" alt="説明">
</picture>
2. 遅延読み込み (Lazy Loading)
<!-- ネイティブのlazy loading -->
<img src="image.jpg" loading="lazy" alt="説明">
<!-- 重要な画像は即座に読み込む -->
<img src="hero.jpg" loading="eager" alt="ヒーロー画像">
3. 画像サイズの最適化
// Next.jsのImageコンポーネント
import Image from 'next/image';
function MyComponent() {
return (
<Image
src="/photo.jpg"
alt="写真"
width={800}
height={600}
quality={75} // 75%の品質で十分
placeholder="blur" // ぼかしプレースホルダー
/>
);
}
JavaScriptの最適化
1. コード分割
// React.lazy()による動的インポート
import { lazy, Suspense } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<div>読み込み中...</div>}>
<HeavyComponent />
</Suspense>
);
}
2. バンドルサイズの削減
// 必要なものだけインポート
// ❌ 悪い例
import _ from 'lodash';
// ✅ 良い例
import debounce from 'lodash/debounce';
// または、よりモダンな代替ライブラリを使用
import { debounce } from 'radash';
3. Tree Shaking
// package.jsonでsideEffectsを明示
{
"name": "my-package",
"sideEffects": false, // または ["*.css"]
}
CSSの最適化
1. クリティカルCSSのインライン化
<head>
<style>
/* Above-the-fold CSS をインライン化 */
.header { background: #000; color: #fff; }
.hero { height: 100vh; }
</style>
<!-- その他のCSSは非同期で読み込み -->
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
</head>
2. 未使用CSSの削除
// PostCSS + PurgeCSSの設定
module.exports = {
plugins: [
require('@fullhuman/postcss-purgecss')({
content: ['./src/**/*.html', './src/**/*.jsx'],
defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
})
]
}
フォントの最適化
1. フォントの読み込み戦略
/* font-displayでフォールバック動作を制御 */
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: swap; /* すぐにフォールバックフォントを表示 */
}
2. プリロード
<head>
<link
rel="preload"
href="/fonts/custom.woff2"
as="font"
type="font/woff2"
crossorigin
>
</head>
キャッシング戦略
1. HTTPキャッシュヘッダー
# Nginxの設定例
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
2. Service Workerによるキャッシング
// service-worker.js
const CACHE_NAME = 'v1';
const urlsToCache = [
'/',
'/styles/main.css',
'/script/main.js'
];
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))
);
});
リソースヒント
<head>
<!-- DNS解決を事前に実行 -->
<link rel="dns-prefetch" href="https://api.example.com">
<!-- 接続を事前に確立 -->
<link rel="preconnect" href="https://api.example.com">
<!-- 重要なリソースを先読み -->
<link rel="preload" href="/critical.css" as="style">
<!-- 次のページを先読み -->
<link rel="prefetch" href="/next-page.html">
</head>
パフォーマンス計測ツール
1. Lighthouse
# CLIでLighthouseを実行
npm install -g lighthouse
lighthouse https://example.com --view
2. Web Vitalsライブラリ
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
getCLS(console.log);
getFID(console.log);
getFCP(console.log);
getLCP(console.log);
getTTFB(console.log);
3. Performance API
// ナビゲーションタイミングの計測
const perfData = performance.getEntriesByType('navigation')[0];
console.log('DOMContentLoaded:', perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart);
console.log('Load:', perfData.loadEventEnd - perfData.loadEventStart);
// リソースタイミングの計測
const resources = performance.getEntriesByType('resource');
resources.forEach(resource => {
console.log(`${resource.name}: ${resource.duration}ms`);
});
まとめ
Webパフォーマンスの最適化は、ユーザー体験の向上に直結する重要な取り組みです。上記のテクニックを組み合わせることで、大幅な改善が見込めます。
重要なのは、計測→改善→計測のサイクルを回し続けること。定期的にパフォーマンスをチェックし、継続的に改善していきましょう!