optimize について
Web のパフォーマンス問題を特定し、改善するためのデザインスキルです。事前計測でボトルネックを絞り、さまざまな端末やネットワーク環境で変更を検証します。
主な機能
- 01Core Web Vitals と実行時指標の計測
- 02読み込み、描画、アニメーションの最適化
- 03バンドルサイズとネットワークリクエストの削減
- 04端末や接続環境を変えた変更の検証
活用シーン
- 01ページの読み込みや操作の遅さの調査
- 02モバイルや低速ネットワークでの応答性改善
- 03パフォーマンス変更によるデグレードの確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ pbakaus/ impeccable --skill optimizeインストール後、Claude Code で/optimizeを入力して読み込まれたか確認します。
詳細
パフォーマンスの問題を特定して修正し、より高速でスムーズなユーザーエクスペリエンスを実現します。
パフォーマンスの問題を評価する
現在のパフォーマンスを把握し、問題を特定します。
-
現状を測定する:
- Core Web Vitals:LCP、FID/INP、CLS のスコア
- 読み込み時間:操作可能になるまでの時間、初回コンテンツ描画
- バンドルサイズ:JavaScript、CSS、画像のサイズ
- 実行時のパフォーマンス:フレームレート、メモリ使用量、CPU 使用率
- ネットワーク:リクエスト数、ペイロードサイズ、ウォーターフォール
-
ボトルネックを特定する:
- 何が遅いのか?(初回読み込み?操作?アニメーション?)
- 原因は何か?(大きな画像?高負荷な JavaScript?レイアウトの頻繁な再計算?)
- どの程度深刻か?(気づく程度?煩わしい?操作を妨げる?)
- 影響を受けるのは誰か?(すべてのユーザー?モバイルのみ?低速な接続環境?)
重要:最適化の前後に測定してください。時期尚早な最適化は時間の無駄です。実際に重要な箇所を最適化しましょう。
最適化の戦略
体系的な改善計画を作成します。
読み込みパフォーマンス
画像を最適化する:
- 最新のフォーマット(WebP、AVIF)を使用する
- 適切なサイズにする(幅 300px の表示に 3000px の画像を読み込まない)
- ファーストビューより下にある画像は遅延読み込みする
- レスポンシブ画像(
srcset、picture要素)を使用する - 画像を圧縮する(品質 80~85% なら、通常は見た目の差がわかりません)
- 配信を高速化するために CDN を使用する
<img
src="hero.webp"
srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
sizes="(max-width: 400px) 400px, (max-width: 800px) 800px, 1200px"
loading="lazy"
alt="Hero image"
/>
JavaScript バンドルを小さくする:
- コード分割(ルート単位、コンポーネント単位)
- ツリーシェイキング(未使用のコードを削除する)
- 未使用の依存関係を削除する
- 重要度の低いコードを遅延読み込みする
- 大きなコンポーネントには動的インポートを使用する
// Lazy load heavy component
const HeavyChart = lazy(() => import('./HeavyChart'));
CSS を最適化する:
- 未使用の CSS を削除する
- 重要な CSS はインライン化し、残りは非同期で読み込む
- CSS ファイルを最小化する
- 独立した領域には CSS の包含を使用する
フォントを最適化する:
font-display: swapまたはoptionalを使用する- フォントをサブセット化する(必要な文字だけにする)
- 重要なフォントをプリロードする
- 適切な場合はシステムフォントを使用する
- 読み込むフォントのウェイトを制限する
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: swap; /* Show fallback immediately */
unicode-range: U+0020-007F; /* Basic Latin only */
}
読み込み戦略を最適化する:
- 重要なリソースを先に読み込む(重要度の低いリソースは非同期読み込みまたは遅延読み込みにする)
- 重要なアセットをプリロードする
- 次に表示される可能性が高いページをプリフェッチする
- オフライン対応やキャッシュにはサービスワーカーを使用する
- 多重化には HTTP/2 または HTTP/3 を使用する
レンダリングパフォーマンス
レイアウトの頻繁な再計算を避ける:
// ❌ Bad: Alternating reads and writes (causes reflows)
elements.forEach(el => {
const height = el.offsetHeight; // Read (forces layout)
el.style.height = height * 2; // Write
});
// ✅ Good: Batch reads, then batch writes
const heights = elements.map(el => el.offsetHeight); // All reads
elements.forEach((el, i) => {
el.style.height = heights[i] * 2; // All writes
});
レンダリングを最適化する:
- 独立した領域には CSS の
containプロパティを使用する - DOM の深さを最小限にする(階層が浅いほど高速です)
- DOM のサイズを小さくする(要素数を減らす)
- 長いリストには
content-visibility: autoを使用する - 非常に長いリストには仮想スクロールを使用する(react-window、react-virtualized)
描画と合成を減らす:
- アニメーションには
transformとopacityを使用する(GPU で高速化されます) - レイアウトプロパティ(width、height、top、left)のアニメーションは避ける
- 負荷の高い処理がわかっている場合に限り、
will-changeを使用する - 描画領域を小さくする(小さいほど高速です)
アニメーションのパフォーマンス
GPU アクセラレーション:
/* ✅ GPU-accelerated (fast) */
.animated {
transform: translateX(100px);
opacity: 0.5;
}
/* ❌ CPU-bound (slow) */
.animated {
left: 100px;
width: 300px;
}
60fps のスムーズな表示:
- 1 フレームあたり 16ms(60fps)を目標にする
- JavaScript によるアニメーションには
requestAnimationFrameを使用する - スクロールハンドラーをデバウンスまたはスロットルする
- 可能な場合は CSS アニメーションを使用する
- アニメーション中に長時間実行される JavaScript を避ける
Intersection Observer:
// Efficiently detect when elements enter viewport
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Element is visible, lazy load or animate
}
});
});
React/フレームワークの最適化
React 固有の最適化:
- 負荷の高いコンポーネントには
memo()を使用する - 負荷の高い計算には
useMemo()とuseCallback()を使用する - 長いリストを仮想化する
- ルートをコード分割する
- レンダリング時にインライン関数を作成しない
- React DevTools Profiler を使用する
フレームワークに依存しない最適化:
- 再レンダリングを最小限にする
- 負荷の高い処理をデバウンスする
- 計算済みの値をメモ化する
- ルートとコンポーネントを遅延読み込みする
ネットワークの最適化
リクエスト数を減らす:
- 小さなファイルを結合する
- アイコンには SVG スプライトを使用する
- 重要度の高い小さなアセットをインライン化する
- 未使用のサードパーティスクリプトを削除する
API を最適化する:
- ページネーションを使用する(すべてを一度に読み込まない)
- 必要なフィールドだけをリクエストするために GraphQL を使用する
- レスポンスを圧縮する(gzip、brotli)
- HTTP キャッシュヘッダーを設定する
- 静的アセットには CDN を使用する
低速な接続環境に合わせて最適化する:
- 接続状況に応じて読み込みを調整する(navigator.connection)
- 楽観的な UI 更新を行う
- リクエストの優先順位を設定する
- プログレッシブエンハンスメントを適用する
Core Web Vitals の最適化
Largest Contentful Paint(LCP < 2.5s)
- ヒーロー画像を最適化する
- クリティカル CSS をインライン化する
- 重要なリソースをプリロードする
- CDN を使用する
- サーバーサイドレンダリングを行う
First Input Delay(FID < 100ms)/INP(< 200ms)
- 長時間のタスクを分割する
- 重要でない JavaScript の読み込みを遅らせる
- 重い計算には Web ワーカーを使用する
- JavaScript の実行時間を短縮する
Cumulative Layout Shift(CLS < 0.1)
- 画像と動画に寸法を設定する
- 既存のコンテンツより上にコンテンツを挿入しない
aspect-ratioCSS プロパティを使用する- 広告や埋め込みコンテンツ用のスペースを確保する
- レイアウトシフトを引き起こすアニメーションを避ける
/* Reserve space for image */
.image-container {
aspect-ratio: 16 / 9;
}
パフォーマンスの監視
使用するツール:
- Chrome DevTools(Lighthouse、Performance パネル)
- WebPageTest
- Core Web Vitals(Chrome UX Report)
- バンドルアナライザー(webpack-bundle-analyzer)
- パフォーマンス監視ツール(Sentry、DataDog、New Relic)
主な指標:
- LCP、FID/INP、CLS(Core Web Vitals)
- Time to Interactive(TTI)
- First Contentful Paint(FCP)
- Total Blocking Time(TBT)
- バンドルサイズ
- リクエスト数
重要:実際のネットワーク環境で、実機を使って測定してください。高速な接続環境でのデスクトップ版 Chrome は、実際の状況を反映していません。
絶対にしないこと:
- 測定せずに最適化する(時期尚早な最適化)
- パフォーマンスのためにアクセシビリティを犠牲にする
- 最適化中に機能を壊す
- あらゆる場所で
will-changeを使う(新しいレイヤーが作成され、メモリを消費します) - ファーストビューのコンテンツを遅延読み込みする
- 大きな問題を無視して細かな最適化にこだわる(まず最大のボトルネックを最適化する)
- モバイルのパフォーマンスを忘れる(デバイスの性能や接続速度が低いことがよくあります)
改善を検証する
最適化の効果をテストします:
- 最適化前後の指標:Lighthouse のスコアを比較する
- リアルユーザーモニタリング:実際のユーザーに対する改善を追跡する
- さまざまなデバイス:最新の iPhone だけでなく、ローエンドの Android 端末でもテストする
- 低速な接続:3G に速度制限して、使用感をテストする
- リグレッションがないこと:引き続き機能が動作することを確認する
- ユーザーが感じる速度:体感として速くなっていますか?
パフォーマンスは機能の一つです。速いエクスペリエンスは、より応答性が高く、洗練され、プロフェッショナルに感じられます。体系的に最適化し、徹底的に測定し、ユーザーが体感するパフォーマンスを優先してください。
コメント
Markdown 対応