Webパフォーマンス最適化の実践テクニック2024
6分で読む
Tech Blog Admin

広告スペース
Slot: article-top
Format: horizontal
本番環境でGoogle AdSenseが表示されます
なぜWebパフォーマンスが重要なのか
Webサイトの表示速度は、ユーザー体験とビジネス成果に直接影響します。Googleの調査によると、ページの読み込み時間が1秒から3秒に増加すると、直帰率が32%上昇します。
Core Web Vitalsの理解と改善
LCP (Largest Contentful Paint)
最大のコンテンツが表示されるまでの時間。目標は2.5秒以内。
// LCPの改善例
// ❌ 悪い例
<img src="/hero-image.jpg" />
// ✅ 良い例
<img
src="/hero-image.jpg"
loading="eager"
fetchpriority="high"
width="1200"
height="600"
/>
FID (First Input Delay) → INP (Interaction to Next Paint)
ユーザーの入力から応答までの遅延。2024年3月からINPに置き換わりました。
// INPの改善:重い処理を分割
// ❌ 悪い例
function processLargeData(data) {
for (let i = 0; i < data.length; i++) {
// 重い処理
complexCalculation(data[i]);
}
}
// ✅ 良い例
async function processLargeData(data) {
const chunkSize = 100;
for (let i = 0; i < data.length; i += chunkSize) {
const chunk = data.slice(i, i + chunkSize);
// メインスレッドを解放
await new Promise(resolve => setTimeout(resolve, 0));
chunk.forEach(item => complexCalculation(item));
}
}
CLS (Cumulative Layout Shift)
視覚的な安定性。目標は0.1以下。
/* CLSの改善 */
/* ❌ 悪い例 */
.image {
/* サイズ指定なし */
}
/* ✅ 良い例 */
.image-container {
aspect-ratio: 16 / 9;
width: 100%;
overflow: hidden;
}
/* またはHTMLで指定 */
<img src="..." width="800" height="450" />
画像最適化のベストプラクティス
1. 次世代画像フォーマットの活用
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="Description" loading="lazy">
</picture>
2. Next.js Image コンポーネントの活用
import Image from 'next/image';
function OptimizedImage() {
return (
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={600}
placeholder="blur"
blurDataURL={blurDataUrl}
priority // LCP画像の場合
sizes="(max-width: 768px) 100vw,
(max-width: 1200px) 50vw,
33vw"
/>
);
}
3. 画像の遅延読み込み
// Intersection Observer を使用した実装
const lazyImages = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.add('loaded');
imageObserver.unobserve(img);
}
});
}, {
rootMargin: '50px 0px' // 50px前から読み込み開始
});
lazyImages.forEach(img => imageObserver.observe(img));
JavaScriptの最適化
1. Code Splitting
// 動的インポート
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <Skeleton />,
ssr: false // 必要に応じて
});
// Route-based splitting
const routes = [
{
path: '/dashboard',
component: lazy(() => import('./pages/Dashboard'))
}
];
2. Tree Shaking
// ❌ 悪い例
import _ from 'lodash';
const result = _.debounce(fn, 300);
// ✅ 良い例
import debounce from 'lodash/debounce';
const result = debounce(fn, 300);
3. Web Workers の活用
// worker.js
self.addEventListener('message', (e) => {
const result = heavyComputation(e.data);
self.postMessage(result);
});
// main.js
const worker = new Worker('/worker.js');
worker.postMessage(data);
worker.addEventListener('message', (e) => {
console.log('Result:', e.data);
});
CSSの最適化
1. Critical CSS
<!-- インラインでクリティカルCSSを配置 -->
<style>
/* ファーストビューに必要なCSS */
.hero { ... }
.header { ... }
</style>
<!-- 残りのCSSは非同期で読み込み -->
<link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
2. CSS-in-JS の最適化
// Emotion with SSR
import { CacheProvider } from '@emotion/react';
import createEmotionServer from '@emotion/server/create-instance';
const cache = createEmotionCache();
const { extractCriticalToChunks, constructStyleTagsFromChunks } =
createEmotionServer(cache);
// サーバーサイド
const emotionChunks = extractCriticalToChunks(html);
const emotionCss = constructStyleTagsFromChunks(emotionChunks);
ネットワーク最適化
1. Resource Hints
<!-- DNS Prefetch -->
<link rel="dns-prefetch" href="//api.example.com">
<!-- Preconnect -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<!-- Prefetch -->
<link rel="prefetch" href="/next-page.js">
<!-- Preload -->
<link rel="preload" href="/font.woff2" as="font" type="font/woff2" crossorigin>
2. Service Worker でキャッシュ戦略
// Cache First 戦略
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request).then((response) => {
return caches.open('v1').then((cache) => {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});
パフォーマンス計測と監視
1. Web Vitals の計測
import { getCLS, getFID, getLCP, getTTFB, getFCP } from 'web-vitals';
function sendToAnalytics(metric: any) {
// Google Analytics 4
gtag('event', metric.name, {
value: Math.round(metric.value),
metric_id: metric.id,
metric_value: metric.value,
metric_delta: metric.delta,
});
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);
getFCP(sendToAnalytics);
2. Performance Observer
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('LCP candidate:', entry.startTime, entry);
}
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
チェックリスト
✅ 画像の最適化(フォーマット、サイズ、遅延読み込み)
✅ Critical CSSの実装
✅ JavaScriptのCode Splitting
✅ フォントの最適化(font-display: swap)
✅ HTTP/2 または HTTP/3の使用
✅ CDNの活用
✅ Gzip/Brotli圧縮
✅ キャッシュ戦略の実装
✅ Third-partyスクリプトの最適化
✅ Core Web Vitalsの定期的な計測
まとめ
Webパフォーマンスの最適化は継続的なプロセスです。Core Web Vitalsを指標として、ユーザー体験を向上させることで、ビジネス成果にも貢献できます。
定期的な計測と改善を繰り返し、高速なWebサイトを維持しましょう!
広告スペース
Slot: article-bottom
Format: rectangle
本番環境でGoogle AdSenseが表示されます