Thinking

[Web] 프론트엔드 개발자가 알아야 할 Core Web Vitals 최적화 실전 가이드 (LCP, INP, CLS)

코딩하는 Jay 2026. 11. 2. 08:56
반응형

안녕하세요. 코딩하는 Jay입니다. 오늘은 현대 웹 개발에서 검색 엔진 최적화(SEO)와 사용자 경험(UX)을 좌우하는 구글의 핵심 웹 지표(Core Web Vitals)의 개념과 실무 최적화 기법에 대해 알아보도록 하겠습니다.

웹 서비스를 배포하고 나면 "왜 우리 사이트는 로딩이 느리게 느껴질까?", "모바일에서 스크롤하거나 버튼을 누를 때 왜 버벅거릴까?" 하는 고민을 한 번쯤 해보셨을 텐데요. 구글은 2024년 기존 FID(First Input Delay)를 폐지하고 인터랙션 반응성을 전면적으로 평가하는 INP(Interaction to Next Paint)를 정식 코어 지표로 도입했습니다.

이제 단순히 초기 로딩 속도만 빠르다고 좋은 점수를 받을 수 없습니다. 오늘은 LCP, INP, CLS의 3대 핵심 지표를 완벽히 이해하고, 실무 프로젝트(React, Next.js 등)에서 점수를 극적으로 개선할 수 있는 핵심 팁을 정리해 보았습니다.


Core Web Vitals 3대 핵심 지표 한눈에 보기

구글이 제시하는 핵심 웹 바이탈 지표는 사용자가 웹페이지를 방문했을 때 느끼는 로딩 속도, 인터랙션 반응성, 시각적 안정성을 측정합니다.

지표 측정 영역 좋은 기준(Good) 주요 원인 및 설명
LCP (Largest Contentful Paint) 로딩 성능 2.5초 이하 뷰포트 내 가장 큰 콘텐츠(이미지, 텍스트 블록)가 렌더링되는 시간
INP (Interaction to Next Paint) 반응성 200ms 이하 클릭, 탭, 키보드 입력 후 다음 화면 프레임이 렌더링될 때까지의 지연 시간
CLS (Cumulative Layout Shift) 시각적 안정성 0.1 이하 페이지 로딩 중 예상치 못하게 요소가 밀려나는 레이아웃 이동의 누적 점수

1. LCP (Largest Contentful Paint) 개선 실전 기법

LCP는 대다수 웹사이트에서 히어로 이미지(Hero Image)나 상단 배너 타이틀이 차지합니다. 2.5초 이내 렌더링을 위한 핵심 조치는 다음과 같습니다.

우선순위 힌트(Priority Hints)와 Preload 적용

상단 주요 이미지는 브라우저가 HTML을 파싱하는 즉시 다운로드할 수 있도록 fetchpriority="high" 속성을 부여하거나 를 설정해야 합니다.

<!-- 상단 히어로 배너 프리로드 -->
<link rel="preload" as="image" href="/images/hero-banner.webp" fetchpriority="high" />

<!-- 이미지 태그에 우선순위 부여 -->
<img src="/images/hero-banner.webp" alt="메인 배너" fetchpriority="high" loading="eager" />

차세대 이미지 포맷(WebP, AVIF) 및 반응형 이미지 서빙

기존 JPEG, PNG 대비 용량을 30~50% 줄여주는 WebP나 AVIF 포맷을 사용하고, 모바일 화면에 불필요하게 4K 해상도 이미지를 내려보내지 않도록 srcset과 sizes를 반드시 지정합니다. Next.js를 사용 중이라면 기본 제공되는 컴포넌트를 활용하면 자동으로 최적화됩니다.


2. INP (Interaction to Next Paint) 최적화: 클릭 즉시 반응하기

기존 FID가 '첫 번째 클릭'의 반응 지연만 봤다면, INP는 사용자가 페이지에 머무는 동안 발생하는 모든 클릭, 탭, 키 입력 중 가장 지연이 심했던 인터랙션을 평가합니다. 200ms 이내로 줄이기 위한 핵심은 메인 스레드를 오래 점유하는 긴 작업(Long Task)을 쪼개는 것입니다.

무거운 연산은 scheduler.yield() 또는 트랜지션으로 양보하기

사용자 입력 직후 복잡한 데이터 필터링이나 대규모 렌더링이 일어나면 화면이 멈칫(Freeze)하게 됩니다. React 18+의 useTransition을 활용하거나 브라우저 최신 API인 scheduler.yield()를 활용해 메인 스레드를 브라우저에 양보해야 합니다.

import { useTransition, useState } from 'react';

function SearchComponent() {
  const [isPending, startTransition] = useTransition();
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    // 1. 긴급한 UI 반응 (인풋 텍스트 즉시 업데이트)
    setQuery(e.target.value);

    // 2. 무거운 필터링 연산은 트랜지션으로 백그라운드 처리
    startTransition(() => {
      const filtered = performHeavyFilter(e.target.value);
      setResults(filtered);
    });
  };

  return <input type="text" value={query} onChange={handleChange} />;
}

3. CLS (Cumulative Layout Shift) 방지: 덜컹거리는 화면 없애기

글을 읽거나 버튼을 누르려는데 갑자기 상단에 광고나 이미지가 뒤늦게 뜨면서 화면이 덜컹 내려앉아 엉뚱한 곳을 클릭해 본 경험이 있으실 겁니다. 이 현상을 막으려면 모든 비동기 리소스의 공간을 미리 확보해야 합니다.

이미지와 비디오에 종횡비(Aspect Ratio) 명시

이미지의 width와 height 속성을 HTML에 반드시 명시하거나 CSS의 aspect-ratio를 선언해 브라우저가 이미지를 다운로드받기 전에도 레이아웃 공간을 예약해 두도록 합니다.

/* 이미지 공간 미리 확보 */
.card-thumbnail {
  width: 100%;
  aspect-ratio: 16 / 9;
  background-color: #f1f3f5; /* 스켈레톤 배경 */
}

동적 광고 및 폰트 레이아웃 시프트 방지

  • 광고 배너 영역: 광고가 로드되기 전 min-height를 지정해 빈 슬롯 공간을 확보합니다.
  • 웹 폰트: FOIT/FOUT로 인한 레이아웃 틀어짐을 막기 위해 CSS font-display: swap과 함께 size-adjust를 활용해 시스템 대체 폰트와의 크기 차이를 일치시킵니다.

측정 도구 및 실무 모니터링 팁

  • 개발 단계 (Lab Data): 크롬 개발자 도구의 Lighthouse 탭 및 Performance 패널에서 Long Task와 렌더링 지연 지점을 프로파일링합니다.
  • 실사용자 환경 (Field Data): PageSpeed Insights와 구글 서치 콘솔(Search Console)의 '코어 웹 바이탈' 리포트를 통해 실제 방문자 기기에서 수집된 75번째 백분위수(p75) 데이터를 주기적으로 확인합니다.

성능 최적화는 최고의 UX이자 SEO입니다

구글 코어 웹 바이탈 최적화는 단순히 검색 순위를 높이기 위한 기술적 트릭이 아닙니다. 모바일 환경에서 사용자가 답답함 없이 부드럽게 탐색할 수 있는 기본적인 웹 완성도를 의미합니다.

오늘 다룬 LCP 우선순위 힌트, INP 메인 스레드 분할, CLS 종횡비 예약 3가지만 프로젝트에 적용해도 전반적인 웹 바이탈 점수가 크게 개선되는 것을 확인하실 수 있을 것입니다. 참고하시기 바랍니다!

반응형