"우리 사이트 빠른데요?"라고 말하는 클라이언트 PC 환경에서 Lighthouse를 돌려보면 모바일 점수가 40점대인 경우가 흔합니다. 체감과 측정값이 다른 이유는 단순합니다. Google은 실사용자(field) 데이터를 기반으로 검색 순위를 평가하기 때문이죠. 이 글에서는 Core Web Vitals 3대 지표 — LCP·CLS·INP — 의 임계값과 측정 방법, 그리고 Next.js 환경에서 자주 무너지는 패턴을 코드와 함께 정리합니다.
왜 Google이 이걸 신경 쓰나
2021년 6월 Page Experience 업데이트 이후, Web Vitals는 검색 순위 신호의 타이브레이커(tie-breaker) 로 작동합니다. 콘텐츠 품질이 비슷한 두 페이지가 있을 때, Web Vitals가 Good 구간인 쪽이 위로 올라옵니다. 한국 시장에서는 모바일 트래픽 비중이 70% 이상이고, 평균 4G 대역폭과 중급 안드로이드(Galaxy A 시리즈 기준 CPU 4-6배 throttling)에서 측정되기 때문에, 데스크톱 Chrome으로 본 인상과 실제 CrUX 데이터의 격차가 큽니다.
CrUX(Chrome User Experience Report)는 28일 rolling window로 75th percentile 값을 집계합니다. 즉, 사용자 4명 중 3명이 Good 구간에 들어와야 통과합니다. 평균값으로 자위하면 안 되는 이유입니다.
LCP — 첫 의미 있는 컨텐츠가 보이기까지
Largest Contentful Paint. viewport 안에서 가장 큰 이미지나 텍스트 블록이 렌더링되는 시점을 측정합니다.
- Good: < 2.5s
- Needs Improvement: 2.5s - 4.0s
- Poor: > 4.0s
LCP의 75%는 결국 "이미지 로딩 시간 + 폰트 FOIT" 입니다. 가장 흔한 실수가 hero 이미지를 lazy-load 처리하는 것입니다. Next.js라면 priority prop과 적절한 sizes 명시가 핵심입니다.
import Image from "next/image"; export default function Hero() { return ( <Image src="/hero.webp" alt="..." width={1920} height={1080} priority sizes="(max-width: 768px) 100vw, 1200px" placeholder="blur" blurDataURL="data:image/jpeg;base64,..." /> ); }
priority를 안 붙이면 브라우저가 lazy-loading 큐에 넣어 LCP가 800ms-1.2s 늦어집니다. 반대로 페이지에 priority 이미지를 5개씩 박는 경우도 있는데, 이러면 preload 경합으로 오히려 느려집니다. viewport 안의 hero 1개에만 부여하세요.
서버 응답(TTFB)이 600ms를 넘으면 LCP는 구조적으로 Good에 들어갈 수 없습니다. CDN 캐시·DB 쿼리·SSR 미들웨어부터 의심해야 합니다.
CLS — 화면이 흔들리지 않아야 한다
Cumulative Layout Shift. 페이지 로드 중 시각적 요소가 예상치 못하게 이동한 거리의 누적 점수입니다.
- Good: < 0.1
- Needs Improvement: 0.1 - 0.25
- Poor: > 0.25
원인은 거의 정해져 있습니다.
- width/height 누락 이미지 —
<img>나next/image에 명시적 크기가 없으면 로드 후 다른 컨텐츠를 밀어냅니다. - 광고/임베드 슬롯 — 동적 삽입되는 iframe은
min-height컨테이너로 미리 자리를 확보하세요. - 웹폰트 FOIT/FOUT — Pretendard·Noto Sans KR을 swap만 걸면 텍스트 폭이 바뀌면서 레이아웃이 튑니다.
폰트 시프트는 font-display: optional과 size-adjust로 잡습니다.
@font-face { font-family: "Pretendard"; src: url("/fonts/Pretendard-Variable.woff2") format("woff2-variations"); font-display: optional; size-adjust: 102%; ascent-override: 92%; }
Next.js next/font/local을 쓰면 빌드 타임에 폰트 metrics를 자동 주입해 CLS를 0에 가깝게 줄여줍니다.
INP — 사용자 입력 반응성 (FID 후속, 2024년 정식 지표)
Interaction to Next Paint. 2024년 3월 FID를 대체한 신규 지표입니다. 페이지 lifetime 동안 발생한 모든 클릭·탭·키 입력 중 가장 느린 응답을 봅니다.
- Good: < 200ms
- Needs Improvement: 200ms - 500ms
- Poor: > 500ms
FID가 첫 입력만 봤다면, INP는 세션 전체를 봅니다. 그래서 SPA에서 라우트 전환 핸들러가 무거우면 가차없이 깨집니다. 주범은 다음입니다.
- Hydration mismatch 후 클라이언트에서 큰 컴포넌트 트리를 동기 렌더
- 300KB+ JS 번들이 메인 스레드 점유 (mid-tier Android에서 1.5s+ blocking)
- 클릭 핸들러 안에서
JSON.parse(largeString)같은 동기 작업
해법은 React 18의 useTransition·startTransition으로 non-urgent update를 분리하고, 무거운 차트·테이블은 Server Component로 전환하는 것입니다.
한국 모바일 환경에서 자주 깨지는 패턴 3가지
| 지표 | Good 임계값 | 측정 도구 | 한국 환경 흔한 원인 |
|---|---|---|---|
| LCP | < 2.5s | Lighthouse, PageSpeed Insights, CrUX | 무거운 hero 이미지 (1MB+ JPG), 폰트 FOIT, TTFB 800ms+ |
| CLS | < 0.1 | Lighthouse, Web Vitals 확장, Layout Shift Regions | 한글 웹폰트 swap, 광고/배너 늦은 삽입, 이미지 크기 미지정 |
| INP | < 200ms | Chrome DevTools Performance, Web Vitals 확장 | 큰 JS 번들, 무거운 클릭 핸들러, 미들 안드로이드 CPU throttling |
특히 한국에서 자주 보이는 안티패턴 3가지:
- 카카오/네이버 SDK 동기 로드 —
<script src="...kakao.js">를 head 동기 삽입하면 LCP가 400-700ms 밀립니다.defer+ 인터랙션 시점에 lazy init 하세요. - 포털 폰트 CDN 의존 — 외부 도메인 RTT가 200ms 이상 추가됩니다. self-host +
preload+font-display: optional로 옮기세요. - 모바일 메뉴 햄버거 클릭 시 라우터 push 후 드로어 애니메이션 동시 실행 — INP가 600ms+ 찍힙니다.
requestIdleCallback이나startTransition으로 라우팅을 분리하세요.
지금 측정하고 시작하는 법
먼저 field data부터 보세요. PageSpeed Insights에 도메인을 넣으면 CrUX 28일 데이터가 나옵니다. lab data(Lighthouse)와 다르면 항상 field가 진실입니다.
그 다음 로컬에서 재현하려면 Chrome DevTools → Performance → CPU 4x slowdown + Fast 4G throttling 설정 후 incognito mode에서 측정하세요. 확장 프로그램이 INP를 30ms씩 늘립니다.
배포 후 모니터링은 web-vitals 라이브러리로 실사용자 데이터를 직접 수집하는 것이 가장 정확합니다. Vercel Analytics·Sentry Performance·Datadog RUM 모두 이를 제공합니다.
빈랩 추천
Web Vitals 점수가 떨어지면 이미지·폰트·JS 번들 중 어디부터 손대야 할지 막연합니다. 빈랩은 제작 단계부터 Next.js 15 App Router 기반으로 LCP·CLS·INP를 모두 Good 구간에 맞춰 출시하고, 출시 후엔 RUM 모니터링으로 회귀를 잡습니다. SEO 인프라 점검은 sitemap.xml과 robots.txt 가이드, 기술 스택 의사결정은 Next.js + Supabase 모던 SMB를 함께 보세요.
핵심 요약
- LCP < 2.5s · CLS < 0.1 · INP < 200ms — 75th percentile field 데이터 기준
- LCP는 hero 이미지
priority+ TTFB 600ms 이하가 출발점 - CLS는 이미지 width/height 명시 +
font-display: optional로 80% 해결 - INP는 JS 번들 크기와 메인 스레드 blocking이 본질, Server Component 적극 활용
- lab data(Lighthouse)와 field data(CrUX)가 다르면 field가 진실
결과로 증명하는 IT 에이전시
대표님의 다음 홈페이지,
30분 무료 진단부터 시작하세요
빈랩이 만든 사이트라면 검색 노출·관리자 페이지·문의 알림이 제작 단계부터 포함됩니다.
30분 무료 진단으로 현재 사이트의 약점 리포트를 받아보실 수 있습니다 — 평균 24시간 이내 회신해 드립니다.
관련 아티클
같은 카테고리네이버 SEO와 구글 SEO 차이 — 한국 SMB가 둘 다 잡는 7가지 실전 가이드
네이버와 구글 검색 알고리즘은 다르게 작동합니다. 한국 SMB가 두 채널 모두에서 상위 노출을 잡기 위한 7가지 실전 차이점과 우선순위를 현장 데이터로 정리합니다.
JSON-LD 구조화 데이터로 검색 결과 풍부하게 만들기 — 한국 사례 5가지
schema.org JSON-LD 표준으로 Google Rich Results를 받는 실전 가이드. Recipe·FAQ·Product·LocalBusiness·Article 한국 사례와 흔한 실수 5가지까지 정리합니다.
sitemap.xml과 robots.txt 제대로 쓰는 법 — 네이버·구글 동시 등록 가이드
robots.txt와 sitemap.xml만 제대로 써도 인덱싱 90%는 해결됩니다. 네이버·구글·빙 동시 등록 절차와 파일 예시까지 7년차 엔지니어의 체크리스트.