모든 이미지에 loading="lazy"를 붙였더니 LCP가 오히려 나빠진 이유
문제 발생
성능을 개선하려고 모든 <img>에 loading="lazy"를 일괄 적용했습니다. 총 전송량은 줄었는데 LCP(Largest Contentful Paint)는 오히려 나빠졌습니다.
<img src="/hero.webp" alt="" loading="lazy" /> <!-- 첫 화면의 큰 이미지 -->원인 분석
loading="lazy"는 뷰포트에 가까워질 때까지 요청을 미룹니다. 화면 아래쪽 이미지에는 정확히 원하는 동작이지만, 첫 화면에 이미 보이는 이미지에 걸면 브라우저가 그 이미지를 늦게 요청하게 됩니다.
LCP는 "첫 화면에서 가장 큰 요소가 그려진 시각"입니다. 히어로 이미지가 보통 그 요소이므로, 그것을 늦추면 지표가 그대로 나빠집니다. 전송량이 줄어든 것은 사실이지만 최적화하려던 지표와는 다른 값입니다.
반대 방향의 도구도 있습니다. fetchpriority는 같은 종류의 리소스들 사이에서 상대적 우선순위를 지정합니다. 브라우저는 기본적으로 이미지를 낮은 우선순위로 다루다가 레이아웃 후에 올리는데, 어느 것이 LCP 후보인지 미리 알려 주면 처음부터 높게 가져갈 수 있습니다.
해결 방안
- 첫 화면 이미지는 lazy를 빼고 우선순위를 올립니다.
<img src="/hero.webp" alt="" width="1200" height="630" fetchpriority="high" />- 첫 화면 밖의 이미지에만 lazy를 씁니다. 목록의 두 번째 화면부터가 대상입니다.
<img src="/thumb.webp" alt="" width="320" height="180" loading="lazy" decoding="async" />width/height를 반드시 적습니다. 지연 로딩이든 아니든, 크기를 모르면 이미지가 도착하는 순간 레이아웃이 밀려 CLS가 발생합니다. 비율만 유지하면 되므로 실제 표시 크기와 같을 필요는 없습니다.- 우선순위를 올릴 대상은 하나만 고릅니다. 여러 이미지에
fetchpriority="high"를 주면 서로 대역폭을 나눠 가져 아무것도 빨라지지 않습니다. "이 화면의 LCP 요소는 무엇인가"를 먼저 정합니다. - 프레임워크의 이미지 컴포넌트에도 같은 개념이 있습니다. Next.js의
next/image는priorityprop이fetchpriority="high"와 preload를 함께 처리합니다. 첫 화면 이미지에만 붙입니다. - 측정으로 확인합니다. 추측 대신 Lighthouse나 실제 사용자 지표(RUM)에서 LCP 요소가 무엇으로 잡히는지 보고 결정합니다 — 히어로가 아니라 헤드라인 텍스트가 LCP인 화면도 흔합니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.