jpskill.com
📦 その他 コミュニティ

performance-vitals

ウェブサイトの表示速度や操作性を改善し、LCP、FID/INP、CLSといった主要指標を最適化することで、ユーザー体験を向上させるための対策を支援するSkill。

📜 元の英語説明(参考)

Enforce Core Web Vitals optimization. Use when building user-facing features, reviewing performance, or when Lighthouse scores drop. Covers LCP, FID/INP, CLS, and optimization techniques.

🇯🇵 日本人クリエイター向け解説

一言でいうと

ウェブサイトの表示速度や操作性を改善し、LCP、FID/INP、CLSといった主要指標を最適化することで、ユーザー体験を向上させるための対策を支援するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o performance-vitals.zip https://jpskill.com/download/18880.zip && unzip -o performance-vitals.zip && rm performance-vitals.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/18880.zip -OutFile "$d\performance-vitals.zip"; Expand-Archive "$d\performance-vitals.zip" -DestinationPath $d -Force; ri "$d\performance-vitals.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して performance-vitals.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → performance-vitals フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

[Skill 名] performance-vitals

パフォーマンスと Core Web Vitals

Core Web Vitals の最適化を強制するスキルです。

2025年の状況

2024年3月: INP (Interaction to Next Paint) が FID に代わる Google 検索ランキングに Core Web Vitals が影響

Core Web Vitals の目標

指標 良好 改善が必要 不良
LCP (Largest Contentful Paint) ≤ 2.5秒 2.5秒 - 4秒 > 4秒
INP (Interaction to Next Paint) ≤ 200ミリ秒 200ミリ秒 - 500ミリ秒 > 500ミリ秒
CLS (Cumulative Layout Shift) ≤ 0.1 0.1 - 0.25 > 0.25

LCP の最適化 (Largest Contentful Paint)

問題の原因

  • 遅いサーバー応答
  • レンダリングをブロックするリソース (CSS, JS)
  • 遅いリソースの読み込み
  • クライアントサイドレンダリング

解決策

1. 画像の最適化

// ❌ BAD: 最適化されていない画像
<img src="/hero.jpg" alt="Hero" />

// ✅ GOOD: Next.js Image コンポーネント
import Image from 'next/image';

<Image
  src="/hero.jpg"
  alt="Hero"
  width={1200}
  height={600}
  priority  // LCP 画像には priority を追加
  placeholder="blur"
  blurDataURL={blurDataUrl}
/>

2. フォントの最適化

// ✅ GOOD: Next.js フォントの最適化
import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',  // FOIT を防止
  preload: true,
});

// CSS
@font-face {
  font-family: 'Custom Font';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: swap;
}

3. Critical CSS のインライン化

// next.config.js
module.exports = {
  experimental: {
    optimizeCss: true,
  },
};

4. プリロード

<!-- 重要リソースのプリロード -->
<link rel="preload" href="/hero.jpg" as="image" />
<link rel="preload" href="/fonts/main.woff2" as="font" crossorigin />
<link rel="preconnect" href="https://api.example.com" />

INP の最適化 (Interaction to Next Paint)

問題の原因

  • 長い JavaScript タスク
  • 過度な DOM サイズ
  • 非効率的なイベントハンドラー

解決策

1. 長いタスクの分割

// ❌ BAD: 長い同期処理
function processLargeData(items: Item[]) {
  items.forEach(item => {
    heavyComputation(item);  // メインスレッドをブロック
  });
}

// ✅ GOOD: チャンク分割 + yield
async function processLargeData(items: Item[]) {
  const CHUNK_SIZE = 100;

  for (let i = 0; i < items.length; i += CHUNK_SIZE) {
    const chunk = items.slice(i, i + CHUNK_SIZE);
    chunk.forEach(item => heavyComputation(item));

    // ブラウザに制御を戻す
    await new Promise(resolve => setTimeout(resolve, 0));
  }
}

2. イベントハンドラーの最適化

// ❌ BAD: 重いハンドラー
<input onChange={(e) => {
  const value = e.target.value;
  validateAllFields();  // 重い演算
  updateUI();
  sendAnalytics();
}} />

// ✅ GOOD: デバウンス + 分離
import { useDeferredValue, useTransition } from 'react';

function SearchInput() {
  const [input, setInput] = useState('');
  const deferredInput = useDeferredValue(input);
  const [isPending, startTransition] = useTransition();

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    setInput(e.target.value);  // 即時更新

    startTransition(() => {
      // 緊急性の低い更新は transition で
      performSearch(e.target.value);
    });
  };

  return <input value={input} onChange={handleChange} />;
}

3. Web Worker の活用

// worker.ts
self.onmessage = (e) => {
  const result = heavyComputation(e.data);
  self.postMessage(result);
};

// main.ts
const worker = new Worker(new URL('./worker.ts', import.meta.url));

worker.postMessage(data);
worker.onmessage = (e) => {
  setResult(e.data);
};

CLS の最適化 (Cumulative Layout Shift)

問題の原因

  • サイズ未指定の画像/動画
  • 動的なコンテンツの挿入
  • ウェブフォントの FOIT/FOUT
  • アニメーション

解決策

1. 画像/動画のサイズ指定

// ❌ BAD: サイズ未指定
<img src="/photo.jpg" alt="Photo" />

// ✅ GOOD: サイズを明示
<img
  src="/photo.jpg"
  alt="Photo"
  width={800}
  height={600}
/>

// ✅ GOOD: aspect-ratio の使用
<div style={{ aspectRatio: '16/9' }}>
  <img src="/video-thumb.jpg" alt="Video" style={{ width: '100%' }} />
</div>

2. 動的コンテンツのスペース確保

// ❌ BAD: スペースなしで動的に挿入
{isLoaded && <Banner />}

// ✅ GOOD: スケルトンでスペースを確保
{isLoaded ? <Banner /> : <BannerSkeleton />}

// ✅ GOOD: min-height でスペースを確保
<div style={{ minHeight: '200px' }}>
  {isLoaded && <DynamicContent />}
</div>

3. フォントの読み込み

/* ✅ GOOD: font-display: swap */
@font-face {
  font-family: 'CustomFont';
  src: url('/font.woff2') format('woff2');
  font-display: swap;
}

/* ✅ GOOD: フォールバックフォントのサイズ調整 */
@font-face {
  font-family: 'CustomFont';
  src: url('/font.woff2') format('woff2');
  font-display: swap;
  size-adjust: 105%;  /* フォールバックフォントとサイズを合わせる */
}

4. アニメーション

/* ❌ BAD: レイアウトプロパティのアニメーション */
.animate {
  transition: width 0.3s, height 0.3s, margin 0.3s;
}

/* ✅ GOOD: transform, opacity のみを使用 */
.animate {
  transition: transform 0.3s, opacity 0.3s;
}

測定ツール

Lighthouse CI

# .github/workflows/lighthouse.yml
name: Lighthouse CI

on: [push]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Lighthouse CI
        uses: treosh/lighthouse-ci-action@v10
        with:
          urls: |
            https://example.com/
            https://example.com/dashboard
          budgetPath: ./lighthouse-budget.json
          uploadArtifacts: true

lighthouse-budget.json

[
  {
    "path": "/*",
    "timings": [
      { "metric": "largest-contentful-paint", "budget": 2500 },
      { "metric": "cumulative-layout-shift", "budget": 0.1 },
      { "metric": "interaction-to-next-paint", "budget": 200 }
    ]
  }
]

web-vitals ライブラリ

import { onCLS, onINP, onLCP } from 'web-vitals';

function sendToAnalytics(metric: Metric) {
  console.log(metric.name, metric.value);

  // Analytics へ送信
  gtag('event', metric.name, {
    value: metric.delta,
    metric_id: metric.id,
    metric_value: metric.value,
    metric_delta: metric.delta,
  });
}

onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);

迅速な最適化チェックリスト

LCP の改善

  • [ ] LCP 画像に priority または preload を設定
  • [ ] 画像フォーマットの最適化 (WebP/AVIF)
  • [ ] サーバー応答時間 < 600ミリ秒
  • [ ] Critical CSS のインライン化
  • [ ] レンダリングをブロックするリソースの削除

INP の改善

  • [ ] Long Task > 50ミリ秒の削除
  • [ ] イベントハンドラーの最適化
  • [ ] 重い演算を Web Worker へ移動
  • [ ] useTransitionuseDeferredValue の活用
  • [ ] サードパーティースクリプトの遅延読み込み

📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Performance & Core Web Vitals

Core Web Vitals 최적화를 강제하는 스킬입니다.

2025 Context

2024년 3월: INP(Interaction to Next Paint)가 FID를 대체 Google Search 랭킹에 Core Web Vitals 영향

Core Web Vitals 목표

지표 Good Needs Improvement Poor
LCP (Largest Contentful Paint) ≤ 2.5s 2.5s - 4s > 4s
INP (Interaction to Next Paint) ≤ 200ms 200ms - 500ms > 500ms
CLS (Cumulative Layout Shift) ≤ 0.1 0.1 - 0.25 > 0.25

LCP 최적화 (Largest Contentful Paint)

문제 원인

  • 느린 서버 응답
  • 렌더 차단 리소스 (CSS, JS)
  • 느린 리소스 로딩
  • 클라이언트 사이드 렌더링

해결 방법

1. 이미지 최적화

// ❌ BAD: 최적화 없는 이미지
<img src="/hero.jpg" alt="Hero" />

// ✅ GOOD: Next.js Image 컴포넌트
import Image from 'next/image';

<Image
  src="/hero.jpg"
  alt="Hero"
  width={1200}
  height={600}
  priority  // LCP 이미지는 priority 추가
  placeholder="blur"
  blurDataURL={blurDataUrl}
/>

2. 폰트 최적화

// ✅ GOOD: Next.js 폰트 최적화
import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',  // FOIT 방지
  preload: true,
});

// CSS
@font-face {
  font-family: 'Custom Font';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: swap;
}

3. Critical CSS 인라인

// next.config.js
module.exports = {
  experimental: {
    optimizeCss: true,
  },
};

4. 프리로드

<!-- 중요 리소스 프리로드 -->
<link rel="preload" href="/hero.jpg" as="image" />
<link rel="preload" href="/fonts/main.woff2" as="font" crossorigin />
<link rel="preconnect" href="https://api.example.com" />

INP 최적화 (Interaction to Next Paint)

문제 원인

  • 긴 JavaScript 태스크
  • 과도한 DOM 크기
  • 비효율적인 이벤트 핸들러

해결 방법

1. 긴 태스크 분할

// ❌ BAD: 긴 동기 작업
function processLargeData(items: Item[]) {
  items.forEach(item => {
    heavyComputation(item);  // 메인 스레드 블로킹
  });
}

// ✅ GOOD: 청크 분할 + yield
async function processLargeData(items: Item[]) {
  const CHUNK_SIZE = 100;

  for (let i = 0; i < items.length; i += CHUNK_SIZE) {
    const chunk = items.slice(i, i + CHUNK_SIZE);
    chunk.forEach(item => heavyComputation(item));

    // 브라우저에 제어권 반환
    await new Promise(resolve => setTimeout(resolve, 0));
  }
}

2. 이벤트 핸들러 최적화

// ❌ BAD: 무거운 핸들러
<input onChange={(e) => {
  const value = e.target.value;
  validateAllFields();  // 무거운 연산
  updateUI();
  sendAnalytics();
}} />

// ✅ GOOD: 디바운스 + 분리
import { useDeferredValue, useTransition } from 'react';

function SearchInput() {
  const [input, setInput] = useState('');
  const deferredInput = useDeferredValue(input);
  const [isPending, startTransition] = useTransition();

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    setInput(e.target.value);  // 즉시 업데이트

    startTransition(() => {
      // 덜 급한 업데이트는 transition으로
      performSearch(e.target.value);
    });
  };

  return <input value={input} onChange={handleChange} />;
}

3. Web Worker 활용

// worker.ts
self.onmessage = (e) => {
  const result = heavyComputation(e.data);
  self.postMessage(result);
};

// main.ts
const worker = new Worker(new URL('./worker.ts', import.meta.url));

worker.postMessage(data);
worker.onmessage = (e) => {
  setResult(e.data);
};

CLS 최적화 (Cumulative Layout Shift)

문제 원인

  • 크기 미지정 이미지/비디오
  • 동적 콘텐츠 삽입
  • 웹폰트 FOIT/FOUT
  • 애니메이션

해결 방법

1. 이미지/비디오 크기 지정

// ❌ BAD: 크기 미지정
<img src="/photo.jpg" alt="Photo" />

// ✅ GOOD: 크기 명시
<img
  src="/photo.jpg"
  alt="Photo"
  width={800}
  height={600}
/>

// ✅ GOOD: aspect-ratio 사용
<div style={{ aspectRatio: '16/9' }}>
  <img src="/video-thumb.jpg" alt="Video" style={{ width: '100%' }} />
</div>

2. 동적 콘텐츠 공간 확보

// ❌ BAD: 공간 없이 동적 삽입
{isLoaded && <Banner />}

// ✅ GOOD: 스켈레톤으로 공간 확보
{isLoaded ? <Banner /> : <BannerSkeleton />}

// ✅ GOOD: min-height로 공간 확보
<div style={{ minHeight: '200px' }}>
  {isLoaded && <DynamicContent />}
</div>

3. 폰트 로딩

/* ✅ GOOD: font-display: swap */
@font-face {
  font-family: 'CustomFont';
  src: url('/font.woff2') format('woff2');
  font-display: swap;
}

/* ✅ GOOD: 폴백 폰트 크기 조정 */
@font-face {
  font-family: 'CustomFont';
  src: url('/font.woff2') format('woff2');
  font-display: swap;
  size-adjust: 105%;  /* 폴백 폰트와 크기 맞춤 */
}

4. 애니메이션

/* ❌ BAD: 레이아웃 속성 애니메이션 */
.animate {
  transition: width 0.3s, height 0.3s, margin 0.3s;
}

/* ✅ GOOD: transform, opacity만 사용 */
.animate {
  transition: transform 0.3s, opacity 0.3s;
}

측정 도구

Lighthouse CI

# .github/workflows/lighthouse.yml
name: Lighthouse CI

on: [push]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Lighthouse CI
        uses: treosh/lighthouse-ci-action@v10
        with:
          urls: |
            https://example.com/
            https://example.com/dashboard
          budgetPath: ./lighthouse-budget.json
          uploadArtifacts: true

lighthouse-budget.json

[
  {
    "path": "/*",
    "timings": [
      { "metric": "largest-contentful-paint", "budget": 2500 },
      { "metric": "cumulative-layout-shift", "budget": 0.1 },
      { "metric": "interaction-to-next-paint", "budget": 200 }
    ]
  }
]

web-vitals 라이브러리

import { onCLS, onINP, onLCP } from 'web-vitals';

function sendToAnalytics(metric: Metric) {
  console.log(metric.name, metric.value);

  // Analytics 전송
  gtag('event', metric.name, {
    value: metric.delta,
    metric_id: metric.id,
    metric_value: metric.value,
    metric_delta: metric.delta,
  });
}

onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);

빠른 최적화 체크리스트

LCP 개선

  • [ ] LCP 이미지에 priority 또는 preload
  • [ ] 이미지 포맷 최적화 (WebP/AVIF)
  • [ ] 서버 응답 시간 < 600ms
  • [ ] Critical CSS 인라인
  • [ ] 렌더 차단 리소스 제거

INP 개선

  • [ ] Long Task > 50ms 제거
  • [ ] 이벤트 핸들러 최적화
  • [ ] 무거운 연산 Web Worker로 이동
  • [ ] useTransition, useDeferredValue 활용
  • [ ] Third-party 스크립트 지연 로딩

CLS 개선

  • [ ] 모든 이미지/비디오 크기 지정
  • [ ] 동적 콘텐츠 공간 확보 (스켈레톤)
  • [ ] font-display: swap 설정
  • [ ] transform/opacity만 애니메이션

Workflow

1. 성능 측정

# Lighthouse CLI
npx lighthouse https://example.com --output=json --output-path=./lh-report.json

# 또는 Chrome DevTools > Lighthouse 탭

2. 문제 진단

LCP > 2.5s?
→ Network 탭에서 LCP 리소스 확인
→ 이미지 최적화 / 프리로드 적용

INP > 200ms?
→ Performance 탭에서 Long Task 확인
→ 태스크 분할 / Web Worker 적용

CLS > 0.1?
→ Layout Shift 원인 요소 확인
→ 크기 지정 / 스켈레톤 적용

3. 모니터링

프로덕션:
- Google Search Console Core Web Vitals
- Real User Monitoring (RUM)
- web-vitals 라이브러리

CI/CD:
- Lighthouse CI
- Performance Budget 설정

References