Core Web Vitals는 Google이 정의한 사용자 경험 핵심 지표로, 검색 순위에도 영향을 미친다. LCP(로딩), INP(상호작용), CLS(시각 안정성) 세 지표가 핵심이며, 2023년 FID가 INP로 교체되었다.
세 가지 핵심 지표
| 지표 | 측정 항목 | 좋음 | 개선 필요 | 나쁨 |
|---|
| LCP | 최대 콘텐츠풀 페인트 (로딩) | ≤2.5s | 2.5~4s | >4s |
| INP | 다음 페인트까지의 상호작용 | ≤200ms | 200~500ms | >500ms |
| CLS | 누적 레이아웃 이동 | ≤0.1 | 0.1~0.25 | >0.25 |
LCP 최적화
html
<!-- 히어로 이미지 우선 로딩 -->
<img src="hero.webp"
alt="히어로"
fetchpriority="high"
loading="eager"
decoding="async">
<!-- 리소스 사전 로딩 -->
<link rel="preload" as="image" href="hero.webp">
<link rel="preload" as="font" href="font.woff2" crossorigin>
INP 최적화
javascript
// 긴 작업 분리: scheduler.yield() 사용
async function processLargeData(items) {
for (let i = 0; i < items.length; i++) {
processItem(items[i]);
// 50개마다 메인 스레드 양보
if (i % 50 === 0) {
await scheduler.yield(); // 또는 setTimeout(0)
}
}
}
// 이벤트 핸들러 최적화
button.addEventListener('click', async (e) => {
// 즉각적인 시각 피드백 먼저
button.classList.add('loading');
// 무거운 작업은 비동기로
await heavyTask();
button.classList.remove('loading');
});
CLS 방지
css
/* 이미지/비디오에 크기 명시 */
img, video {
aspect-ratio: 16/9;
width: 100%;
}
/* 광고/동적 콘텐츠 공간 예약 */
.ad-container {
min-height: 250px;
}
/* 폰트 로딩 중 레이아웃 보호 */
@font-face {
font-family: 'MyFont';
font-display: optional; /* 폰트 없으면 시스템 폰트 유지 */
}
측정 방법
javascript
import { onLCP, onINP, onCLS } from 'web-vitals';
onLCP(metric => sendAnalytics('LCP', metric.value));
onINP(metric => sendAnalytics('INP', metric.value));
onCLS(metric => sendAnalytics('CLS', metric.value));
관련 개념