성능 최적화

[ Frontend > 웹 최적화 ]

[프론트엔드] 웹 성능 지표

 Carrot Yoon
 2025-09-30
 15

웹 성능 지표

이 문서는 웹 페이지 성능을 평가하는 지표와 이를 개선하는 방법을 안내해요.
목표는 사용자 경험을 최적화하는 방법까지 간단하게 학습하는 것입니다.


1. 성능 지표 소개

성능 지표는 LCP, FCP, CLS, TTFB 등 다양하게 있어요. 그리고 구글과 web.dev에서는 성능을 나타내는 지표들 중에 핵심 지표를 선정해요. 과거에는 LCP, FID, CLSgoogle 문서에서 핵심 web vitals 지표라고 소개 했어요. 하지만 이 성능 지표는 계속 업데이트 되고 있습니다.

1.1 Core Web Vitals (핵심 지표)

2026년 1월 기준 Core Web Vitals와 평가 기준이에요.

  • LCP (Largest Contentful Paint)

    • 페이지에서 가장 큰 콘텐츠(이미지, 비디오, 텍스트 블록 등)가 렌더링 시작하는 시간

    • 권장 기준: 페이지 로딩이 시작된 후 2.5초 2초 이내에 LCP가 발생. (26년도 부터 2초 이하 동문)

    • 로딩 경험 지표

  • CLS (Cumulative Layout Shift)

    • 페이지 로딩 중 레이아웃 이동 정도

    • 권장 기준: 0.1 0.08 미만

    • 시각적 안정성 지표

  • FCP (First Contentful Paint)

    • DOM에 첫 콘텐츠가 렌더링되는 시간 → 초기 로딩 체감 속도

    • 권장 기준: 1.5초 (새로 편입)

  • INP (Interaction to Next Paint)

    • 모든 상호작용의 지연을 종합적으로 측정하고, 화면이 실제로 다시 그려질 때까지의 시간까지 포함

    • 권장 기준: 150ms (FID 대체)

1.2 기타 성능 지표 (공식 Core Web Vital이 아닌 지표, 사라지거나 보조용)

기타 성능 지표들도 한번 알아보아요.

  • TTFB (Time to First Byte)

    • 서버가 첫 바이트를 응답하는 시간 → 서버 성능 및 네트워크 문제

    • 권장 기준: 300ms 이하

  • TTI (Time to Interactive)

    • 페이지가 실제 상호작용 가능해지는 시간 (페이지가 사용자와의 상호작용에 완전히 준비되기까지의 시간)

    • 권장 기준: 모바일일 경우 5초 미만이지만, 상호작용 영향을 많이 받아 INP 측정을 권장함.

  • TBT(Total Blocking Time)

    • FCP 시점과 TTI 사이의 시간

    • 권장 기준: 모바일 300ms, 데스크탑 100ms

  • SI (Speed Index)

    • 화면이 시각적으로 얼마나 빨리 그려지는지 평가 (동영상 처럼 캡처하여 얼마나 빨리 채워지는지 측정)

    • 권장 기준: 컨텐츠에 따라 많이 달라져서 명확한 값은 없음. 모바일: 0~3.4초, 데스크탑: 0.~2.5초

  • FID (First Input Delay) => 2024년 3월 부터 INP가 공식 Core Web Vitals FID를 대체한다고 해요.

    • 사용자가 페이지와 처음 상호작용(클릭, 스크롤 등)한 후 브라우저가 화면을 다시 그리는 데 걸리는 시간

    • 권장 기준: 100ms 80ms 이하

    • 상호작용 반응성 지표, Chrome 도구는 24년 9월 9일부터 이 지표의 가용성 보장하지 않음.

1.3 페이지 경험 평가 요소

  • 모바일 친화성: 모바일 환경에서 원활한 UX 제공

  • HTTPS 보안: 안전한 페이지 제공

  • 침해적이지 않은 광고: 사용자 경험을 방해하지 않는 광고 배치

  • 명확한 콘텐츠 구분: 콘텐츠와 광고/기타 요소 혼동 방지


2. 핵심 지표의 문제 원인과 해결 비법

이제 4개의 핵심지표인 LCP, FCP, CLS, INP의 수치가 낮게 나오는 원인들을 함께 알아봐요.

2.1. LCP (Largest Contentful Paint) 지연

서버 응답 지연 (TTFB)

  • 원인

    • 백엔드 데이터베이스 쿼리, 동적 페이지 생성 시간 증가

    • 호스팅 인프라 성능 부족 (공유 호스팅)

    • CDN 미사용으로 인한 물리적 거리 문제

  • 해결법

    • Server-Timing 헤더로 병목 지점 측정 및 최적화

    • CDN 사용하여 RTT(Round Trip Time) 감소

    • 정적 HTML 캐싱 (ETag 또는 짧은 캐시 수명 적용)

    • 압축 활성화 (Brotli > gzip)

렌더링 차단 CSS

  • 원인

    • <head>의 대용량 CSS 파일이 다운로드될 때까지 렌더링 차단

    • CSS @import 선언으로 연속 요청 발생 (긴 네트워크 요청 체인)

  • 해결법

    • 중요 CSS를 <style> 태그로 인라인 처리

    • 나머지 CSS는 <body> 끝에 배치하거나 비동기 로드

    • CSS 압축 및 사용하지 않는 CSS 제거

    • <link> 요소 사용 (@import 대신)

    • media 속성으로 조건부 로딩 (media="print")

이미지 최적화 부족

  • 원인

    • 과도하게 큰 이미지 (뷰포트 크기 대비)

    • WebP/AVIF 등 최신 포맷 미사용

    • 적절한 압축 미적용

  • 해결법

    • srcset/sizes 속성으로 반응형 이미지 제공

    • WebP, AVIF 형식 사용 (<picture> 요소로 대체 제공)

    • 이미지 압축 (손실/무손실, Squoosh, ImageOptim 활용)

    • LCP 이미지에 fetchpriority="high" 적용

    • <link rel="preload"> + fetchpriority="high"로 LCP 이미지 우선 로드

잘못된 lazy loading

  • 원인

    • 초기 뷰포트 내 이미지에 loading="lazy" 적용

  • 해결법

    • 스크롤 없이 보이는 이미지는 loading="eager" (기본값) 사용

    • 뷰포트 밖 이미지만 loading="lazy" 적용

웹 글꼴 로딩 지연

  • 원인

    • 외부 @font-face 선언이 늦게 발견됨

    • 서드파티 폰트 서비스의 크로스 오리진 지연

  • 해결법

    • <link rel="preload" as="font" crossorigin> 사용

    • @font-face 선언을 <style>로 인라인 처리

    • 자체 호스팅 (Google Fonts 대신)

    • WOFF2 형식만 사용 (최고 압축률)

    • 폰트 서브셋 생성 (필요한 글리프만 => 영어 글꼴만 필요하면 영어만 따로 추출하기)

동영상 최적화 부족

  • 원인

    • 과도하게 큰 동영상 파일

    • 비효율적 코덱 사용

  • 해결법

    • FFmpeg로 압축 (-crf 옵션, -an으로 오디오 제거)

    • WebM (VP9/AV1), MP4 (H.264) 다중 형식 제공

    • poster 속성으로 포스터 이미지 지정

    • poster 이미지가 LCP인 경우 preload

2.2 FCP (First Contentful Paint) 지연

렌더링 차단 리소스

  • 원인

    • <head>의 대용량 CSS/JS가 파싱 및 실행될 때까지 렌더링 차단

    • 초기 렌더링에 불필요한 코드까지 로드

  • 해결법

    • CSS 압축 및 중요 CSS 인라인 처리

    • JavaScript에 defer 또는 async 속성 적용

    • type="module" 사용 (자동 defer)

    • 파서 차단 스크립트 최소화

    • Critical CSS 적용 (스크롤 없이 보이는 영역만 inline style하거나 html style 태그로 css 선언)

    • 코드 스플릿

    • lazy import 적용

리소스 압축/캐싱 미적용

  • 원인

    • Gzip/Brotli 미사용

    • CDN 캐싱 미설정

  • 해결법

    • Brotli 압축 우선 적용 (gzip 대체)

    • 정적 리소스 압축 (1KiB 이상)

    • 동적 압축보다 정적 압축 선호

    • Cache-Control 헤더 설정

리디렉션

  • 원인

    • 동일 출처/교차 출처 리디렉션으로 추가 HTTP 요청

  • 해결법

    • 불필요한 리디렉션 제거

    • 내부 링크를 올바른 URL로 직접 연결

    • 후행 슬래시 일관성 유지 (example.com/page/ => example.com/page 또는 그 반대로 리다이렉트)

서버 응답 지연 (TTFB)

  • LCP 섹션의 TTFB 해결법과 동일

2.3 CLS (Cumulative Layout Shift) 증가

이미지/동영상 크기 미지정

  • 원인

    • <img>, <video>에 width/height 미설정

    • 이미지 로드 시 레이아웃 재계산 발생

  • 해결법

    • 항상 width, height 속성 명시

    • aspect-ratio CSS 속성 사용

웹 글꼴 FOUT/FOIT

  • 원인

    • font-display: swap으로 대체 폰트 → 웹 폰트 교체 시 레이아웃 변경

    • font-display: block으로 텍스트 깜박임

  • 해결법

    • font-display: optional 사용 (100ms 내 로드 실패 시 대체 폰트 유지)

    • font-display: fallback (짧은 차단 + swap)

    • 대체 폰트와 웹 폰트의 메트릭 유사하게 조정 (혹은 CLS 안일으키는 폰트로 변경)

    • preload로 웹 폰트 빠른 로딩

동적 삽입 콘텐츠

  • 원인

    • 배너, 광고, 알림이 기존 콘텐츠 위에 갑자기 삽입

    • JavaScript로 DOM 동적 추가

  • 해결법

    • 동적 콘텐츠를 위한 공간 미리 예약

    • min-height CSS 속성으로 공간 확보

    • 스켈레톤 UI 사용

iframe 지연 로드

  • 원인

    • <iframe> 크기 미지정으로 로드 시 레이아웃 변경

  • 해결법

    • width, height 속성 명시

    • loading="lazy" 적용 (뷰포트 밖)

2.4 INP (Interaction to Next Paint) 지연

메인 스레드 블로킹

  • 원인

    • 무거운 JavaScript 실행 (파싱, 컴파일, 실행)

    • 대규모 렌더링 작업

    • 긴 작업(Long Tasks, 50ms 이상)

  • 해결법

    • JavaScript 압축 및 uglification

    • 코드 분할로 필요한 코드만 로드

    • defer, async 속성 사용

    • 클라이언트 사이드 렌더링 최소화

    • 코드 스플릿

    • lazy import 적용

    • DOM 조작과 연관없는 라이브러리는 partytown 웹 워커 활용

    • 쓰로틀링, 디바운싱 적용

파서 차단 JavaScript

  • 원인

    • <script> (defer/async 없이)가 HTML 파싱 차단

  • 해결법

    • <script defer> 사용 (HTML 파싱 완료 후 실행)

    • <script async> 사용 (다운로드 즉시 실행)

    • <script type="module"> 사용 (자동 defer)

    • 스크립트를 <body> 끝에 배치

서드파티 스크립트

  • 원인

    • 광고, 분석, 채팅 위젯 등이 메인 스레드 점유

    • iframe 삽입으로 추가 리소스 로드

  • 해결법

    • <iframe loading="lazy"> 적용

    • 사용자 상호작용 전까지 가짜 UI 표시

    • React Live Chat Loader, lite-youtube-embed 사용

불필요한 리렌더링

  • 원인

    • React/Vue에서 과도한 컴포넌트 리렌더

  • 해결법

    • 메모이제이션 (React.memo, useMemo)

    • 컴포넌트 분리 및 최적화

CSS 애니메이션 성능

2.5 공통 최적화 기법

리소스 힌트

리소스를 빠르게 찾을 수 있도록 힌트를 주는 기법이에요. dns-prefetch < preconnect < prefetch < preload 순으로 강력하게 리소스를 찾아와요.

  • <link rel="dns-prefetch"> - DNS 조회만 조기 실행

  • <link rel="preconnect"> - 교차 출처 연결 조기 수립 (DNS + TCP + TLS)

  • <link rel="prefetch"> - 향후 필요 리소스 낮은 우선순위 로드(다음 페이지에 쓰일 파일 미리 받는데 사용)

  • <link rel="preload"> - 중요 리소스 우선 로드 (이미지, 폰트같이 렌더링에 바로 필요한 경우 사용)

Fetch Priority API

  • fetchpriority="high" - LCP 이미지, 중요 리소스

  • fetchpriority="low" - 썸네일, 덜 중요한 이미지

서비스 워커 사전 캐싱 (웹 워커 아님...)

  • Workbox로 정적 리소스 미리 캐싱

  • 캐시 전용 전략으로 즉시 로드

  • 오프라인 지원

추측 규칙 (Speculation Rules)

  • 페이지 prefetch/prerender로 탐색 속도 향상

  • Quicklink 라이브러리로 뷰포트 내 링크 자동 prefetch


3. 성능 지표 측정하기

성능 측정할 수 있는 도구는 다양해요. WebVital을 보는 라이브러리나, 크롬의 lighthouse 혹은 performance 탭, 기타 성능 측정해주는 사이트가 있어요. 이 중에서 PageSpeed Insights 사이트는 휴대전화와 데스크톱으로 웹사이트 성능 측정을 해줘요. 이 블로그 홈화면 홈페이지 속도를 PageSpeed Insights 사이트로 측정해볼게요. 값은 매번 달라져서 20점 이상도 차이날 수 있습니다.

아래 같이 사이트를 통해 간단하게 측정해봤어요.

image.webp

image.webp

휴대전화의 경우가 거의 대부분 더 성능이 안좋게 나와요. 그리고 기기로 직접 테스트하면 기기 상태마다 속도가 많이 달라집니다.


4. 마무리

이렇게 성능 지표들에 대해 자세히 알아봤습니다. 그리고 각 지표를 개선하는데 서로 영향이 있다는 것도 개선 방법을 공부하며 알았습니다. 저가 만든 블로그도 위에 적혀있는 방법들 대부분 적용하고 있습니다. 그래서 Lighthouse 측정시 웹 성능은 대부분 높은 점수를 받고 있습니다. 웹 성능 최적화 그렇게 어렵지 않습니다!! 여러분들도 찾아서 하나씩 적용해 보세요.


참고자료