---
type: knowledge
domain: frontend
status: active
last-reviewed: 2026-07-27
---

# 웹 성능 실전

> 한 줄 정의
> 측정 → 예산 → 최적화 순서로 로딩·인터랙션 성능을 지키는 실전 원리. 렌더링 전략·상태 설계는 [[프론트엔드 원리]] — 여기는 "왜 느린가"와 "무엇부터 고치나"를 다룬다.

## 제1원칙 — 측정 없는 최적화는 미신이다

- 개발 머신은 유저 기기가 아니다: **CPU 4x 스로틀 + 느린 네트워크**로 재봐야 유저의 체감이 나온다.
- Lab 지표(Lighthouse)와 Field 지표(실제 유저 RUM)는 다르다 — lab은 재현·디버깅용, 판정은 field의 75퍼센타일(모바일·데스크톱 구분).
- 최적화 순서는 워터폴 차트의 **위에서부터** — 뒤쪽 300ms를 줄여봐야 앞쪽 3초가 그대로면 의미 없다.

## Core Web Vitals — 지표별 1순위 용의자

| 지표 | 목표 | 1순위 용의자 | 처방 |
|------|------|-------------|------|
| LCP (최대 콘텐츠 표시) | ≤ 2.5s | 히어로 이미지·웹폰트·렌더 차단 리소스 | 히어로만 `fetchpriority="high"` + preload, 나머지 lazy |
| INP (인터랙션 반응) | ≤ 200ms | 메인 스레드 독점 (거대 JS·긴 핸들러) | 긴 작업 쪼개기, 무거운 계산은 지연·워커로 |
| CLS (레이아웃 이동) | ≤ 0.1 | 치수 없는 이미지·광고·동적 삽입 콘텐츠 | 모든 미디어에 width/height, 자리 미리 확보 |

> [!WARNING] CLS는 로딩 후에도 쌓인다
> 폰트 교체(FOUT), 늦게 뜨는 배너, 스켈레톤→실콘텐츠 크기 불일치가 단골. "로딩 끝났으니 통과"가 아니다.

## 성능 예산 — 선언이 아니라 CI 게이트

| 페이지 유형 | JS (gzip) | CSS |
|------------|-----------|-----|
| 랜딩·마케팅 | < 150kb | < 30kb |
| 앱 페이지 | < 300kb | < 50kb |
| 마이크로사이트 | < 80kb | < 15kb |

- 예산은 문서에 적는 게 아니라 **빌드에서 깨지게** 만든다 (번들 크기 검사를 CI에).
- 번들 비대의 단골: 거대 유틸 라이브러리 전체 import, 아이콘 팩 전체, 차트 라이브러리 즉시 로드. 무거운 라이브러리는 동적 import가 기본값.

## 이미지 — 성능 사고의 최대 지분

- 모든 이미지에 명시적 width/height (CLS의 최대 원인 차단).
- 히어로 1장만 `loading="eager"` + `fetchpriority="high"` — 나머지는 전부 `loading="lazy"`.
- 포맷은 AVIF/WebP + 폴백. **렌더 크기를 한참 넘는 원본 배포 금지** — 4000px 원본을 400px 박스에 넣는 것이 가장 흔한 낭비다.

## 폰트

- 패밀리 2개 상한 (명확한 예외 근거 없이 3개째 금지).
- `font-display: swap` + 서브셋 — 한글 폰트는 서브셋 없으면 MB 단위다.
- preload는 진짜 크리티컬한 weight 1~2개만. 전부 preload하면 preload가 아니다.

## 애니메이션 — 컴포지터 위에서만

- 허용 속성: `transform` · `opacity` · `clip-path` (+ `filter` 아껴서).
- **layout 속성(width·height·top·left·margin·padding·font-size) 애니메이션 금지** — 매 프레임 리플로우가 INP를 죽인다.
- `will-change`는 좁게 걸고 끝나면 제거. 스크롤 핸들러 대신 IntersectionObserver.

## 로딩 전략 요약

1. 크리티컬 above-the-fold CSS만 인라인 (근거 있을 때)
2. 히어로 이미지 + 크리티컬 폰트만 preload
3. 비크리티컬 CSS/JS는 defer
4. 서드파티 스크립트는 async/defer + 정말 필요한 페이지에서만

## 안티패턴

- "일단 다 만들고 나중에 최적화" — 아키텍처 문제(요청 워터폴, 번들 구조)는 나중에 못 고친다.
- 스피너를 오래 보여줘서 느림을 가리기 — 지연은 UX로 덮지 말고 원인을 줄인다.
- 성능 점수 100점 집착 — 목표는 점수가 아니라 **목표 기기에서의 체감**이다.

## 관련 문서

- [[프론트엔드 원리]] — 렌더링 전략·데이터 패칭
- [[접근성 실전]] — 같은 폴더의 품질 짝
- [[프론트엔드-체크리스트]] — 배포 전 점검
- [[UI 시각 체계]] · [[디자인 시스템]] — 시각 자산 규율
- [[지표와 실험]] — 성능 개선의 전환 효과 검증
- [[00_프론트엔드 허브]] — 05_프론트엔드 진입점
