본문으로 건너뛰기
← 블로그로 돌아가기
튜토리얼 2025년 10월 20일

웹 성능 최적화 — 이미지, 폰트, 레이아웃 시프트 잡기

Lighthouse 100점을 위한 실전 웹 성능 최적화. 이미지, 폰트, CLS 해결법.

성능 최적화 Core Web Vitals 이미지 폰트

왜 성능이 중요한가

Google은 Core Web Vitals를 검색 랭킹 요소로 사용한다. 느린 사이트는 검색 순위가 낮아지고, 사용자 이탈률도 높아진다.

Core Web Vitals 세 가지:

  • LCP (Largest Contentful Paint): 주요 콘텐츠 로딩 — 2.5초 이내
  • INP (Interaction to Next Paint): 인터랙션 반응 — 200ms 이내
  • CLS (Cumulative Layout Shift): 레이아웃 흔들림 — 0.1 이하

Karnel Labs 사이트는 Lighthouse Performance 100점이다. 어떻게 달성했는지 정리한다.

이미지 최적화

이미지는 웹 페이지에서 가장 큰 리소스다. 최적화하지 않으면 LCP를 망친다.

1. 포맷 선택

PNG → 투명 배경이 필요한 경우에만
JPEG → 사진에 적합하지만, WebP가 더 낫다
WebP → 대부분의 경우 최적 (30% 더 작은 파일)
AVIF → WebP보다 작지만 브라우저 지원이 제한적

2026년 기준 WebP가 가장 안전한 선택이다. 모든 모던 브라우저가 지원한다.

2. 크기 지정

<!-- 나쁜 예: 크기 없음 → CLS 유발 -->
<img src="/hero.webp" alt="Hero" />

<!-- 좋은 예: 크기 명시 → 브라우저가 공간을 미리 확보 -->
<img src="/hero.webp" alt="Hero" width="1200" height="630" />

widthheight를 명시하면 브라우저가 이미지 로딩 전에 공간을 확보한다. CLS가 0이 된다.

3. 레이지 로딩

뷰포트 밖의 이미지는 나중에 로딩한다.

<!-- 히어로 이미지: 즉시 로딩 -->
<img src="/hero.webp" alt="Hero" loading="eager" fetchpriority="high" />

<!-- 하단 이미지: 레이지 로딩 -->
<img src="/feature.webp" alt="Feature" loading="lazy" />

fetchpriority="high"는 LCP 이미지에 사용한다. 브라우저에게 이 이미지를 최우선으로 다운로드하라고 알려준다.

4. 반응형 이미지

<img
  src="/hero-800.webp"
  srcset="/hero-400.webp 400w, /hero-800.webp 800w, /hero-1200.webp 1200w"
  sizes="(max-width: 640px) 400px, (max-width: 1024px) 800px, 1200px"
  alt="Hero"
/>

모바일에서 1200px 이미지를 다운로드할 필요가 없다. srcset으로 화면 크기에 맞는 이미지를 제공한다.

폰트 최적화

웹 폰트는 렌더링을 차단할 수 있다. 폰트가 로딩될 때까지 텍스트가 안 보이거나(FOIT), 기본 폰트로 보이다가 바뀌는(FOUT) 현상이 발생한다.

1. preconnect

폰트 서버와 미리 연결을 맺어둔다.

<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />

DNS 조회 + TCP 연결 + TLS 핸드셰이크 시간을 절약한다.

2. font-display

@font-face {
  font-family: 'Geist';
  src: url('/fonts/geist.woff2') format('woff2');
  font-display: swap;
}

font-display: swap은 폰트 로딩 중 시스템 폰트를 먼저 보여준다. 텍스트가 바로 보이므로 LCP가 좋아진다.

3. 서브셋팅

한글 폰트는 글리프가 수천 개라 파일이 크다. 사용하는 글자만 추출하면 크기를 90%까지 줄일 수 있다.

# pyftsubset으로 서브셋 생성
pip install fonttools brotli
pyftsubset font.ttf --output-file=font-subset.woff2 --flavor=woff2 \
  --text-file=used-characters.txt

CDN에서 제공하는 폰트(Google Fonts, jsDelivr)는 자동으로 서브셋을 적용한다.

CLS (레이아웃 시프트) 잡기

CLS는 사용자가 보고 있는 동안 레이아웃이 밀리는 현상이다. 버튼을 누르려는데 광고가 로딩되면서 다른 걸 눌러본 경험이 있을 것이다.

주요 원인과 해결

원인해결
이미지 크기 미지정width/height 명시 또는 aspect-ratio
웹 폰트 FOUTfont-display: optional 또는 size-adjust
동적 콘텐츠 삽입min-height로 공간 미리 확보
광고 영역고정 크기 컨테이너 사용

aspect-ratio

이미지 크기를 모를 때 비율로 공간을 확보한다.

.hero-image {
  aspect-ratio: 16 / 9;
  width: 100%;
  object-fit: cover;
}

측정 도구

  • Lighthouse: Chrome DevTools → Lighthouse 탭
  • PageSpeed Insights: 실제 사용자 데이터(CrUX) 기반
  • Web Vitals Extension: Chrome 확장으로 실시간 CWV 모니터링

Karnel Labs 사이트 성능

항목점수
Performance100
LCP0.5초
INP0ms (JS가 거의 없으므로)
CLS0

비결:

  • Astro로 JS 최소화
  • 이미지에 width/height + loading=“lazy”
  • 폰트 preconnect + CDN 서브셋
  • Cloudflare 엣지 캐시

정리

웹 성능 최적화는 세 가지에 집중하면 된다. 이미지를 WebP로 적절한 크기에 제공하고, 폰트를 preconnect + swap으로 처리하고, 모든 동적 요소에 공간을 미리 확보한다. Lighthouse 100은 특별한 기술이 아니라, 기본기의 결과다.