I will check the files in the directory to find the content that needs translation. I will view the `current_job.json` file to check the source content for translation. I will view the `tmp_source.json` file. I will view the `translation_changelog.log` file to understand the context of the translation task. I will view the `stateless_translate.py` file to understand how translation tasks are processed. I will view the `find_results.txt` file to see if there is any other context. Largest Contentful Paint 이미지 최적화
단계별 LCP 이미지 최적화 가이드
Largest Contentful Paint 이미지 최적화하기
이 가이드는 Largest Contentful Paint (LCP) 허브의 일부다. 대부분의 웹사이트에서 LCP 요소는 이미지다. 이미지를 잘못 처리하면 LCP 점수가 떨어진다. 이 글은 이미지를 빠르게 로드하는 모든 기술을 다룬다.
Google에 따르면 인터넷의 모든 페이지뷰(데스크톱 및 모바일 포함) 중 65%만이 '좋음(good)' Largest Contentful Paint 점수를 받는다. 이는 페이지뷰의 35%가 기준에 미달하고 있음을 뜻하며, 이미지 처리 실수가 주된 원인 중 하나다. 이 글은 이미지가 Largest Contentful Paint 요소가 될 때 흔히 발생하는 모범 사례 패턴과 실수를 분석한다.
LCP 팁: 이미지 최적화뿐만 아니라 Largest Contentful Paint의 모든 세부 사항을 마스터하고 싶다면 Largest Contentful Paint 섹션을 확인하라. 네 가지 핵심 요소를 최적화하는 방법을 보여준다:
- Time to First Byte: 브라우저가 HTML을 받기 위해 대기해야 하는 시간이다. 주로 서버 대기 시간이 차지하지만 리디렉션, 연결 시간, 암호화 등도 포함된다.
- Load Delay: LCP 요소가 로드를 시작할 수 있었던 시점과 실제 로드를 시작한 시점 사이의 간격이다. Resource Load Delay 전체 가이드를 읽어보라.
- Resource Load Time: LCP 리소스를 로드하는 데 걸리는 시간이다. 압축과 미니피케이션을 최적화하면 속도를 높일 수. Resource Load Duration 전체 가이드를 읽어보라.
- Render Delay: 리소스가 최적화되어 있어도 브라우저가 다른 작업(보통 스타일시트 다운로드나 무거운 JavaScript 처리)으로 바쁘면 LCP 렌더링이 지연된다. Element Render Delay 전체 가이드를 읽어보라.
이 모든 요소가 중요하지만, LCP 요소가 이미지인 경우(대부분 그렇다) 가능한 한 빨리 로드되도록 조치할 수 있는 간단한 방법들이 있다.
Table of Contents!
- Largest Contentful Paint 이미지 최적화하기
- Largest Contentful Paint 실험
- 1. LCP 대상 제어: 텍스트 우선 전략
- 2. 가장 빠른 이미지 포맷 사용하기
- 3. 반응형 이미지 사용하기
- 4. 화면 크기에 맞게 이미지 크기 조절하기!
- 5. LCP 이미지 Eager 로딩 사용하기
- 6. LCP 이미지 Preload하기
- 7. LCP 이미지에서 페이드인(Fade-In) 애니메이션 제거하기
- 8. LCP 요소 셀프 호스팅하기
- 9. LCP 요소에 클라이언트 사이드 렌더링(CSR) 피하기
- 10. 레이아웃 시프트를 방지하기 위한 공간 확보
- 11. 메인 스레드 차단 감사(Audit)하기
- 관련 LCP 최적화 가이드
Largest Contentful Paint 실험
나는 항상 다른 사람들의 말을 듣고 배우되 그대로 믿지는 말라고 한다. 잘못된 정보를 전파하는 자칭 '전문가'들이 너무 많다. 그래서 LCP 요소를 최적으로 로드하지 않을 때 어떤 일이 일어나는지 직접 확인할 수 있도록 완전 자동화된 LCP 실험을 만들었다. GitHub에서 LCP Test를 확인하거나 라이브 데모를 실행해 보라.
여러 LCP 시나리오를 자동으로 테스트하고 결과를 보여준다. 아래에서 이 시나리오들을 다루며 LCP 이미지 요소의 속도가 빨라지거나 느려지는 이유와 원리를 설명하겠다.

1. LCP 대상 제어: 텍스트 우선 전략
이미지 기반 Largest Contentful Paint를 개선하는 가장 빠른 방법은 이미지를 사용하지 않는 것이다. 이상하게 들리겠지만 내 말을 믿어라. 설명하겠다.
텍스트가 이미지보다 빠른 이유. 성능 차이는 요청 파이프라인에서 발생한다. 텍스트 노드(<h1> 또는 <p> 등)는 메인 HTML 문서의 일부다. 별도의 리소스 요청이 없으며, 렌더링은 CSS에 의해서만 차단된다. 반면 이미지는 자체 HTTP 요청이 필요한 외부 리소스다. 이는 CSS 차단에 더해 네트워크 레이턴시(DNS, TCP, TLS, 다운로드 시간)를 추가로 유발한다. 이 차이가 성능 차이를 만드는 핵심 원인이며, LCP 대상을 제어하는 방식이 강력한 전문가 수준의 전략인 이유다.

그렇다면 이미지와 텍스트 중 무엇을 선택해야 할까? 이미지는 중요하며 사이트를 시각적으로 매력적이게 만든다. 하지만 Core Web Vitals는 어떤 요소가 LCP가 되는지 신경 쓰지 않는다. LCP 요소가 텍스트 기반 요소일 경우, 대개 First Contentful Paint와 동시에 발생한다.
그렇다면 텍스트 기반 Largest Contentful Paint 요소로 전환해야 할까? 그것은 상황에 따라 다르다. 이미지는 중요하고 사이트를 시각적으로 매력적으로 만든다. 따라서 지루한 옛날식 텍스트 요소로 바꾸라고 주장하지는 않을 것이다. 하지만 실수도 일어난다. "우발적 LCP(Accidental LCP)" 안티패턴의 희생양이 된 카테고리 페이지당 1달러씩만 받았어도 부자가 되었을 것이다. 이는 페이지 상단(above the fold)에 설명용 카테고리 텍스트를 추가하는 것을 "깜빡"하여, lazy loading된 상품 이미지가 LCP가 되고 로드 시간이 몇 초씩 지연되는 현상이다. 디자이너가 주요 헤드라인 앞에 큰 히어로 배너를 DOM의 맨 위에 배치할 때 자주 발생하며, 브라우저는 더 느린 LCP 대상을 선택할 수밖에 없게 된다.
2. 가장 빠른 이미지 포맷 사용하기
마지막 1바이트까지 짜내는 법이나 WebP 대 AVIF의 완벽한 설정에 대한 뜨거운 논쟁은 접어두고 한 가지 사실에 동의하자. JPEG나 PNG 같은 오래된 포맷은 WebP나 AVIF 같은 현대적인 포맷에 비해 크고 느리다. 이미지 최적화 기법에 대한 전체적인 개요는 이미지 최적화 가이드를 참조하라.

일반적인 원칙으로서 LCP 이미지에는 손실 압축 WebP 또는 AVIF 버전을 제공해야 한다(모든 이미지에 이 포맷들을 사용하는 것이 더 좋지만, 여기서는 LCP에 집중하자). WebP 지원율이 약 95%이고 AVIF 지원율이 92%이므로 오래된 fallback 이미지도 함께 제공하는 것이 합리적이다. 이를 위해 최신 포맷을 지원하는 브라우저에만 해당 포맷을 제공하는 '점진적 향상(progressive enhancement)' 방식을 사용한다.
디코딩 속도와 압축률의 트레이드오프
AVIF는 최고의 압축률(가장 작은 파일 크기)을 제공하지만, 복잡한 알고리즘 때문에 WebP에 비해 렌더링 가능한 이미지로 디코딩하는 데 더 많은 CPU 전력이 필요할 수 있다. 이는 브라우저의 래스터라이저(Rasterizer) 스레드에서 발생하는 CPU 바운드 작업으로, Element Render Delay를 직접적으로 증가시킨다. 파일 크기가 작은 AVIF는 더 빠르게 다운로드될 수 있지만, 디코딩 시간이 길어지면 특히 모바일 기기에서 그 이점이 상쇄될 수 있다. Chrome DevTools의 Performance 패널에서 LCP 요소와 관련된 오래 실행되는 "Decode Image" 작업을 찾아 이를 진단할 수 있다. 이것이 보인다면 다운로드 시간뿐만 아니라 디코딩 속도가 병목 구간이라는 명확한 신호다.
전문가 통찰: JPEG XL의 사례. 진정한 전문가 가이드라면 JPEG XL을 다루어야 한다. 이 포맷은 특히 기존 JPEG를 손실 없이 재압축할 수 있어 레거시 사이트에 큰 이점을 주며, AVIF에 없는 점진적 디코딩(progressive decoding)을 지원하는 기술적으로 매우 우수한 포맷이다. 하지만 Chrome에서 지원이 중단된 후 브라우저 지원 범위가 넓지 않다는 결정적인 단점이 있다. 이 때문에 아직 일반적인 웹 서비스에 사용하기는 어렵지만, 미래를 위해 지켜볼 만한 포맷이다.
<picture> 요소 사용하기: <picture> 요소를 사용하면 브라우저가 지원하지 않는 이미지 포맷을 건너뛰고 처리 가능한 첫 번째 포맷을 선택할 수 있다. 방법은 다음과 같다:
<picture> <source srcset="img.avif" type="image/avif"> <source srcset="img.webp" type="image/webp"> <img src="img.jpg" alt="이미지" width="123" height="123"> </picture>
포맷 네고시에이션과 반응형 크기의 결합
최고의 성능을 내려면 단일 <picture> 요소 내에서 포맷 선택 기능과 반응형 이미지 크기를 결합해야 한다. 이렇게 하면 모든 사용자가 자신의 기기에 최적화된 포맷과 최적의 크기를 제공받을 수 있다. 브라우저는 <source> 요소를 위에서 아래로 평가하여 지원하는 첫 번째 포맷을 선택한 다음, srcset 및 sizes 속성을 사용하여 올바른 해상도를 선택한다.
<picture>
<source
type="image/avif"
srcset="hero-400w.avif 400w, hero-800w.avif 800w, hero-1200w.avif 1200w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 800px, 1200px">
<source
type="image/webp"
srcset="hero-400w.webp 400w, hero-800w.webp 800w, hero-1200w.webp 1200w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 800px, 1200px">
<img
src="hero-800w.jpg"
srcset="hero-400w.jpg 400w, hero-800w.jpg 800w, hero-1200w.jpg 1200w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 800px, 1200px"
alt="히어로 이미지를 설명하는 대체 텍스트"
width="1200" height="675"
fetchpriority="high">
</picture>
이 패턴은 브라우저에 포맷과 해상도의 최적 조합을 선택할 수 있는 완전한 자율성을 제공한다. 해당 포맷을 지원하는 브라우저를 사용하는 모바일 사용자는 작은 크기의 AVIF 파일을 받고, 구형 데스크톱 브라우저는 알맞은 크기의 JPEG로 fallback 처리된다.
콘텐츠 네고시에이션(content negotiation) 사용하기
콘텐츠 네고시에이션을 사용하면 서버가 브라우저 지원 여부에 따라 다른 이미지 포맷을 제공할 수 있다. 브라우저는 Accept 헤더를 통해 지원하는 포맷을 알린다. 예를 들어 Chrome의 경우 이미지에 대한 Accept 헤더는 다음과 같다:
Accept: image/avif,image/webp,image/apng,image/*,*/*;q=0.8
그 후 서버 측에서 accept 헤더를 읽고, 해당 헤더를 기반으로 '최적의 포맷'을 제공한다.
3. 반응형 이미지 사용하기
LCP 이미지를 최적화할 때는 크기가 정말 중요하다. 가장 쉽게 성과를 낼 수 있는 방법 중 하나는 사용자 화면에 잘 보이면서도 가능한 한 작은 크기의 이미지를 제공하는 것이다. 불필요하게 큰 이미지는 아무런 쓸모가 없다. 대역폭을 낭비하고 로드 시간을 지연시킬 뿐이며, 특히 느린 네트워크 연결 상태이거나 모바일 기기를 사용하는 사용자에게 더 치명적이다.
픽셀을 낭비하지 않으려면 다음 단계를 따르라:
반응형 이미지:
srcset 속성을 사용해 사용자 기기에 맞춰 다양한 이미지 크기를 제공하라. 이렇게 하면 작은 기기에는 작은 이미지가 제공되어 LCP 속도를 높일 수 있다.
sizes 속성이 중요한 이유
w 디스크립터가 있는 srcset을 사용하면서 sizes 속성을 누락하는 것은 흔하면서도 뼈아픈 실수다. sizes 속성이 없으면 브라우저는 기본값인 100vw(viewport 너비의 100%)로 간주할 수밖에 없다. 즉, 큰 데스크톱 화면에서 이미지가 실제로는 500px 크기의 작은 열에만 표시되더라도 브라우저는 srcset 목록에서 아주 거대한 이미지를 다운로드하게 된다. 좋은 재료(srcset)를 준비하고도 조리법(sizes)을 빠뜨려 대역폭이 낭비되고 LCP가 느려지는 셈이다. sizes 속성은 필요한 레이아웃 컨텍스트를 제공하여 다양한 viewport 브레이크포인트에서 이미지가 실제로 얼마나 넓게 표시될지 브라우저에 알려주고, 브라우저가 지능적인 다운로드 선택을 하도록 돕는다.
w 대 x 디스크립터 이해하기
srcset 속성은 두 종류의 디스크립터를 지원한다. viewport에 따라 이미지 크기가 변하는 반응형 디자인의 경우, w(너비) 디스크립터를 선택하는 것이 훨씬 우수하며 필수적이다. 이 디스크립터는 sizes 속성과 결합하여 브라우저가 레이아웃에서 렌더링되는 크기를 기준으로 가장 적절한 이미지를 선택할 수 있게 한다. 더 단순한 x(기기 픽셀 비율) 디스크립터는 화면의 픽셀 밀도만 고려하고 레이아웃 내에서 이미지가 실제로 얼마나 크게 표시되는지는 무시하므로, 아이콘 같은 고정 크기 이미지에만 적합하다.
<img src="img.jpg" srcset="img-400px.jpg 400w, img-800px.jpg 800w, img-1200px.jpg 1200w" sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px" alt="이미지" width="123" height="123">
4. 화면 크기에 맞게 이미지 크기 조절하기!
필요 이상으로 큰 이미지를 서빙하지 마라. viewport에서 LCP 요소가 600px 너비로만 표시된다면 이미지 크기도 그보다 크지 않게 하라. 정말이지, 매일 이런 문제가 발생하는 것을 본다! 검사하려면 이미지를 우클릭하고 '검사(inspect-element)'를 선택하라. 개발자 도구가 열리고 이미지 HTML이 파란색 배경으로 강조 표시된다. 이제 이미지의 렌더링 크기(443 x 139px)가 실제 이미지의 고유 너비(1090x343px)보다 훨씬 작음을 확인할 수 있다. 이는 실제보다 거의 3배나 큰 것이며, 이미지 크기를 조절했다면 파일 크기를 최소 50%는 줄일 수 있었을 것이다.

5. LCP 이미지 Eager 로딩 사용하기
LCP 성능을 극대화하려면 화면에 표시되는 LCP 요소를 Eager 로딩해야 한다(그리고 즉시 보이지 않는 이미지는 lazy loading한다). 이는 LCP 최적화에서 가장 흔히 발생하는 실수 중 하나이며, lazily 로딩된 LCP 이미지 수정하기 글에서 자세히 설명한다.
Eager 로딩: LCP 요소(보통 above-the-fold 콘텐츠)는 항상 Eager 로딩되어야 한다. 그래야 최대한 빨리 나타나서 Largest Contentful Paint 렌더링에 걸리는 시간이 줄어든다. 기본적으로 이미지는 다른 설정이 없는 한 Eager 로딩되지만, LCP 이미지에 loading="lazy"를 설정하지 않았는지 다시 한번 확인하라. lazy loading 설정은 LCP를 크게 지연시키고 Core Web Vitals 점수에 악영향을 준다. loading="eager"는 브라우저의 기본 동작이므로 속성을 완전히 생략해도 결과는 동일하다는 점을 이해하는 것이 중요하다. 핵심은 loading="lazy" 속성이 절대로 존재하지 않도록 보장하는 것이다.
개발자 경고: lazy 로딩된 이미지는 preload scanner에 의해 큐에 추가되지 않는다. preload scanner는 중요한 리소스를 즉시 대기열에 넣는 매우 빠른 보조 HTML 스캐너다. preload scanner가 우회되면 브라우저는 '보이는 이미지'를 대기열에 넣기 전에 렌더링 엔진 작동이 완료될 때까지 대기해야 한다. 브라우저가 기본(native) loading="lazy" 속성을 평가하려면, 먼저 모든 render-blocking CSS를 다운로드하고 파싱하여 렌더 트리를 빌드해야 한다. 레이아웃 계산이 완료된 후에야 브라우저가 해당 이미지가 viewport 내에 있는지 판단할 수 있다. 즉, 전체 CSS가 LCP 이미지 다운로드를 차단하는 의존성이 되며, 이는 성능에 큰 재앙이다.
<img src="lcp-image.jpg" alt="메인 이미지" width="800" height="400">
below the fold에 표시되는 이미지(페이지가 처음 로드될 때 보이지 않는 이미지)는 lazy loading을 사용하는 것이 맞다. 사용자가 스크롤하여 이미지 근처에 올 때까지 로딩을 지연시킴으로써 LCP 요소와 같이 더 중요한 콘텐츠를 위한 대역폭을 확보할 수 있다. 이처럼 lazy loading은 양날의 검이다. 올바르게 사용하면 LCP 속도가 빨라지지만, 잘못 사용하면 느려진다!
<img src="non-visible-image.jpg"
alt="보조 이미지"
loading="lazy"
width="800" height="400">
균형을 맞추는 방법은? 중요한 콘텐츠(LCP 이미지 같은)는 Eager 로딩하고, 덜 중요한 리소스와 below the fold 이미지는 lazy loading하는 것이다!
6. LCP 이미지 Preload하기
LCP 이미지를 preload하면 HTML 상에서 자연스럽게 발견되기 전에 브라우저가 즉시 가져오도록 지시할 수 있다. preload에 관한 전체 가이드는 LCP 이미지 preload하기 전용 문서를 참고하라.
LCP 이미지를 Preload해야 하는 이유
브라우저가 페이지를 로드할 때 HTML, 스타일시트, 스크립트를 특정 순서대로 처리한다. 간혹 LCP 이미지가 체인의 훨씬 뒤에서 참조되면 브라우저가 필요한 시점보다 늦게 이미지를 발견하게 된다. LCP 이미지를 preload하면 이 이미지가 중요하므로 즉시 로드해야 한다는 사실을 브라우저에 미리 알려서, 가장 큰 요소를 렌더링하는 데 발생하는 지연 시간을 줄일 수 있다.
LCP 이미지를 Preload하는 방법
<link rel="preload"> 태그를 사용하여 브라우저가 로딩 프로세스 극초기에 LCP 이미지를 가져오기 시작하도록 설정할 수 있다.
<link rel="preload" href="lcp-image.jpg" as="image" type="image/jpeg">
이를 통해 LCP 이미지가 처음부터 브라우저 큐에 포함되어, 이미지가 CSS나 스크립트 안에 묻혀 있을 때 흔히 발생하는 대기 현상을 방지할 수 있다.
전문가 통찰: 반응형 Preload와 fetchpriority
반응형 이미지에는 단순한 preload만으로는 부족하다. 성능을 갉아먹는 중복 다운로드를 피하려면, preload 링크 자체에 imagesrcset 및 imagesizes 속성을 사용하여 <img> 태그의 로직을 그대로 미러링해야 한다. 이것이 최고 성능을 내는 사이트와 그렇지 않은 사이트를 구분 짓는 전문가 수준의 구현 방법이다.
<!-- <head> 내부 -->
<link rel="preload" as="image"
href="lcp-image-800w.jpg"
imagesrcset="lcp-image-400w.jpg 400w, lcp-image-800w.jpg 800w"
imagesizes="(max-width: 600px) 400px, 800px">
<!-- <body> 내부 -->
<img src="lcp-image-800w.jpg"
srcset="lcp-image-400w.jpg 400w, lcp-image-800w.jpg 800w"
sizes="(max-width: 600px) 400px, 800px"
alt="..." width="800" height="450" fetchpriority="high">
<img> 태그에 fetchpriority="high"를 포함하면 fallback이 제공되어, preload가 지원되지 않는 경우에도 이미지의 우선순위가 높게 유지된다. 이는 이중 안전장치를 마련하는 접근 방식이다. preload가 다운로드를 조기에 시작하고, fetchpriority가 대역폭 경쟁에서 승리하도록 확실히 보장한다.
기억하라: 너무 많은 리소스를 preload하면 브라우저에 과부하를 주어 성능이 저하될 수 있으므로 LCP 이미지에만 사용하라. Core Web Vitals에서 가장 중요한 요소에만 집중하라.
7. LCP 이미지에서 페이드인(Fade-In) 애니메이션 제거하기
페이드인 애니메이션은 시각적으로 매력적일 수 있지만, 숨겨진 LCP 병목 구간이다. LCP 요소(대개 이미지)에 페이드인 효과를 사용하면 애니메이션이 완료될 때까지 브라우저는 LCP로 카운트하지 않는다. 이로 인해 LCP 측정 타이밍이 지연되고 성능 메트릭에 심각한 피해를 줄 수 있다.
전문가 통찰: 애니메이션 지연 메커니즘
이 문제는 페이드인에만 국한되지 않는다. 슬라이드인(예: transform: translateX(-100%)로 시작)이나 줌 효과(예: transform: scale(0.5)로 시작)처럼 처음에 보이지 않거나 화면 밖에 있던 요소를 전환하는 모든 애니메이션에 적용된다. LCP 로직은 가장 큰 요소가 시각적으로 안정되고 완성되는 시점을 측정하도록 설계되었다. 여전히 애니메이션 중인 요소는 안정된 상태로 간주하지 않는다. 이로 인해 LCP의 하위 단계인 Element Render Delay가 직접적으로 증가한다. 브라우저가 이미 이미지를 다운로드했음에도 애니메이션이 끝날 때까지 마지막 프레임을 그리지 못하도록 인위적으로 제어되기 때문이다.

LCP 측정은 애니메이션이 끝난 후에 발생한다: 브라우저는 요소가 완전히 표시될 때만 LCP가 완료된 것으로 판단한다. 페이드인 애니메이션이 있으면 이미지나 콘텐츠가 완전히 나타날 때까지 타이머가 계속 작동하므로, LCP 점수에 몇 초가 쉽게 더해질 수 있다.
단순하게 유지하라: LCP 요소가 가능한 한 빨리 표시되도록 하려면 페이드인 효과를 피하라. 트랜지션이나 애니메이션 없이 이미지가 즉시 로드되고 표시되도록 하라.
LCP 이미지에서는 페이드인을 생략하라. 시각적 효과는 성능 저하를 감수할 만큼의 가치가 없다.
8. LCP 요소 셀프 호스팅하기
LCP 이미지를 셀프 호스팅하라. 제3자(third-party) 서버에 의존하면 통제 불가능한 지연이 발생하여 LCP와 전반적인 페이지 성능이 떨어질 수 있다.
이렇게 생각해 보라: LCP 요소를 셀프 호스팅하지 않는 것은 이웃에게 끊임없이 설탕을 빌리러 가는 것과 같다. 매번 이웃집으로 걸어가 문 앞에서 기다리며 그들이 집에 있기를 바라야 한다. LCP를 위해 제3자 서버에 의존하는 것은 웹사이트가 외부 리소스를 계속 기다리게 만들어 로드 시간을 늦춘다. 셀프 호스팅은 설탕을 주방에 보관하는 것과 같다. 빠르고 직접적이며 안정적이다.
외부 의존성 줄이기: LCP 요소(예: 이미지)가 제3자 서버에 호스팅되면 해당 서버의 속도, 가용성 및 추가적인 왕복 지연 시간(RTT)에 영향을 받게 된다. 셀프 호스팅은 이러한 불확실성을 없애주고, 본인 소유의 서버에서 직접 이미지를 전송할 수 있게 하여 더 빠르고 안정적인 제공을 보장한다.
전문가 통찰: 단일 Origin으로서의 현대적 CDN
핵심 원칙은 새로운 origin 연결(DNS, TCP, TLS)을 최소화하는 것이다. 가장 진보된 아키텍처는 현대적 CDN을 전체 도메인의 리버스 프록시로 사용하여 이를 달성한다. 브라우저 관점에서는 오직 하나의 origin(예: www.yourdomain.com)에만 연결하므로 연결 패널티가 완전히 배제된다. 그런 다음 CDN은 보이지 않는 곳에서 요청을 지능적으로 라우팅하여 origin 서버에서 동적 콘텐츠를 가져오고, 엣지 캐시에서 이미지와 같은 정적 자산을 전송한다. 이 단일 연결이 HTTP/3를 통해 작동할 때 단일화된 origin, 단축된 연결 설정 시간, 그리고 Head-of-Line 차단 완화 등 모든 이점을 누릴 수 있다.
캐싱 및 최적화 활용하기: 셀프 호스팅을 하면 캐싱 전략을 최대한 활용할 수 있으며, 특히 CDN을 사용하는 경우 사용자에게 가장 가까운 서버에서 이미지를 서빙할 수 있다. 이렇게 하면 LCP 요소를 로드하는 데 걸리는 시간이 줄어들어 더 빠른 렌더링이 가능해진다.
이미지 최적화 제어 권한: 셀프 호스팅을 하면 제3자 처리에 의존하지 않고 압축, 리사이징, 포맷 선택 등 이미지가 최적화되는 방식을 직접 제어할 수 있다. 이로써 빠른 로딩에 완벽히 부합하도록 이미지를 조율할 수 있다.
9. LCP 요소에 클라이언트 사이드 렌더링(CSR) 피하기
클라이언트 사이드 렌더링(CSR)은 LCP에 최악의 영향을 미칠 수 있는 행위 중 하나다. LCP 요소(보통 큰 이미지, 텍스트 블록, 비디오)가 JavaScript를 통해 클라이언트 측에서 렌더링되는 경우, 브라우저가 중요 콘텐츠를 표시하기 전에 스크립트 다운로드, 파싱, 실행을 기다려야 하므로 LCP 시간이 늘어나는 결과를 초래한다.
렌더링 지연: CSR 방식을 쓰면 브라우저가 JavaScript를 처리한 후에만 LCP 요소가 표시되므로 요소의 노출이 대폭 지연될 수 있다. 이 과정이 길어질수록 LCP 점수는 나빠진다. 스크립트 처리에 소요되는 매 초는 사용자가 가장 중요한 콘텐츠를 보기 위해 기다려야 하는 시간으로 직결된다.
전문가 통찰: CSR이 LCP를 저해하는 이유
LCP를 다룰 때 CSR로 인한 가장 주요한 성능 손실은, 브라우저의 고속 preload scanner로부터 LCP 이미지를 숨기게 된다는 점이다. 이 스캐너의 역할은 초기 HTML에서 리소스를 찾아 즉시 가져오는 것이다. 이미지가 JavaScript로 렌더링되면 이 스캐너에 감지되지 않아 불필요하고 기나긴 발견 지연(discovery delay)이 생겨난다.
서버 사이드 렌더링(SSR) 또는 정적 렌더링으로 전환하라: LCP 요소를 서버 측에서 렌더링하거나 정적 HTML 응답의 일부로 포함하면, 브라우저가 JavaScript 실행을 기다리지 않고 이미지를 즉시 로드하여 표시할 수 있다. 브라우저가 HTML을 로드하기 시작할 때 곧바로 LCP 요소를 렌더링할 수 있으므로 LCP 타이밍이 대폭 개선된다.
크리티컬 패스(critical path)에서 JavaScript 최소화하기: 일부 클라이언트 측 스크립트가 불가피한 경우, 해당 스크립트가 LCP 요소의 렌더링을 차단하지 않도록 하라. 중요하지 않은 스크립트는 defer나 async 처리하여 LCP 노출이 지연되는 일을 미연에 방지해야 한다.
10. 레이아웃 시프트를 방지하기 위한 공간 확보
<img> 태그에 항상 명시적인 width 및 height 속성을 포함하라. 이는 브라우저가 이미지를 다운로드하기 전에 이미지의 가로세로 비율(aspect ratio)을 계산하고 레이아웃 상에 적절한 공간을 미리 확보하게 만드는 중요한 지침이다.
전문가 통찰: 현대적인 width 및 height 동작 방식
흔한 오해 중 하나는 이러한 속성들이 이미지를 비반응형으로 만든다는 것이다. 현대 브라우저에서는 더 이상 사실이 아니다. 브라우저는 이 HTML 속성들을 사용하여 종횡비를 계산하고 공간을 확보하지만, CSS에서 width: 100%; height: auto;로 설정되어 있다면 이미지는 여전히 완벽하게 반응형으로 작동한다. 이 속성들을 제공하는 것은 CSS aspect-ratio 속성만 단독으로 사용하는 것보다 더 우수하다. 브라우저가 render-blocking CSS가 다운로드되고 파싱되기도 전에 공간을 확보할 수 있어 중요한 시점을 선점하게 되기 때문이다.
CSS 배경 이미지(Background Image) 처리
이 원칙은 CSS background-image의 컨테이너 역할을 하는 요소에도 똑같이 적용된다. 레이아웃 시프트가 흔히 생기는 원인 중 하나는 처음에 높이가 0으로 축소되어 있던 <div>가 배경 이미지가 적용되면서 갑자기 커지는 현상이다. 이를 방지하려면 컨테이너 요소에 직접 CSS aspect-ratio 속성을 설정하여 처음부터 필요한 공간을 확보하라.
11. 메인 스레드 차단 감사(Audit)하기
LCP 이미지가 완벽하게 최적화되고 우선순위가 지정되었더라도, 브라우저의 main thread가 무거운 JavaScript를 실행하느라 바쁘면 최종 렌더링이 지연될 수 있다. 흔히 이러한 차단(blocking)의 원인은 분석 도구, 광고 또는 고객 지원 위젯 등을 위한 제3자 스크립트다. 이 스크립트들이 CPU를 독점하면 Element Render Delay가 증가한다. Chrome DevTools의 Performance 패널을 이용해 초기 로드 과정에서 long-running task를 식별하고 그 원인을 찾은 뒤, 초기 렌더링에 필수적이지 않은 스크립트는 지연(defer)시키거나 제거하라. 이 주제에 관한 더 자세한 정보는 Element Render Delay 가이드를 참고하라.
관련 LCP 최적화 가이드
이미지 최적화는 전체 퍼즐의 한 조각에 불과하다. 각 LCP 단계별로 전용 가이드가 제공된다:
- LCP 문제 진단 및 해결: field data 및 lab tools를 활용하여 LCP 문제를 찾고 해결하는 상세한 진단 방법론.
- Resource Load Delay: preload, fetchpriority, 그리고 최적의 HTML 구조를 활용하여 브라우저가 LCP 리소스를 최대한 조기에 발견하도록 한다.
- Resource Load Duration: 압축, CDN 설정, 네트워크 최적화를 통해 다운로드 시간을 단축한다.
- Element Render Delay: main thread를 비워두어 브라우저가 다운로드 직후 LCP 요소를 즉시 그릴 수 있도록 한다.