웹페이지 접속 후 화면에 이미지가 표시되기까지 걸리는 시간은 페이지 로딩 속도를 인지하는 데 큰 영향을 준다. 브라우저는 기본적으로 HTML 문서를 파싱하면서 리소스의 우선순위를 스스로 판단해 로드하지만, 우리가 원하는 만큼 최적화된 결과를 보장하지는 않는다. 특히 화면의 첫인상을 좌우하는 중요한 이미지라면, 브라우저의 판단에만 의존하지 않고 명시적인 최적화 전략이 필요하다.
내가 작업하는 사이트도 LCP 개선을 위해 LCP 요소에 사용되는 이미지를 먼저 표시하고자 했고, 이를 위해 알아봤던 이미지 로드와 관련된 최적화 방법 세 가지를 소개하려고 한다.
미리 요청하기 - preload
중요한 이미지를 더 빠르게 로드하려면 브라우저가 해당 리소스를 요청하는 시점을 앞당길 수록 좋다.
HTML 문서 내 이미지 리소스가 <img> 태그로 명시되어 있다면, 브라우저의 프리로드 스캐너(Preload Scanner)가 이를 감지하여 HTML 문서 파싱이 끝나기 전에 미리 로드할 수 있다. 하지만 중요한 이미지가 동적으로 삽입되거나 명시되지 않은 경우, preload를 사용하여 리소스를 명시적으로 요청하는 것이 효과적이다.
Preload는 <head> 태그 안에 선언하여 브라우저가 문서를 파싱하는 초기 단계에서 중요한 리소스를 요청하도록 지시하는 방법이다. 이는 DOM이 완전히 준비되기 전에도 리소스를 다운로드할 수 있게 도와준다.
<head>
<link rel="preload" href="hero-image.jpg" as="image">
</head>
동시에 요청하는 수 줄이기 - 레이지 로딩 (Lazy Loading)
기본적으로 브라우저는 화면에 보이지 않는 이미지까지 동시에 요청을 진행한다. 사용 가능한 네트워크 대역폭은 한정되어 있으므로 여러 요청이 동시에 진행되면 경합이 발생한다. 당장은 보여줄 필요가 없는 이미지들은 요청을 하지 않는 것이 대역폭 경합을 줄이고 중요한 이미지를 빠르게 로드 하는 데 도움이 될 것이다. 이럴 때 사용하는 것이 레이지 로딩이다.
이미지 레이지 로딩을 설정하면, 화면에 보이지 않는 이미지들은 실제로 사용자가 해당 위치에 도달할 때까지 로딩되지 않는다. 이는 특히 많은 이미지가 포함된 페이지나 모바일 환경에서 큰 성능 향상을 가져온다. 이미지 레이지 로딩을 구현하는 방법은 크게 두 가지로 나눌 수 있다.
Intersection Observer API, 이벤트 핸들러를 이용해 구현
화면에 보이는 이미지를 로드하도록 개발자가 직접 레이지 로드 기능을 구현하는 방법이다. 로드 범위에 대한 세밀한 조정이 가능하고 원하는 로직을 자유롭게 추가할 수 있으나 코드가 복잡해진다는 단점이 있다.
브라우저 레벨 레이지 로딩 사용 (loading 속성)
loading="lazy" 속성을 사용하는 방법으로, 브라우저가 자체적으로 지원하는 기능을 이용한다.
<img src="image.png" loading="lazy" alt="…" width="200" height="200">
loading 속성에 지원되는 값은 다음과 같다.
- lazy: 리소스가 표시 영역에서 계산된 거리에 도달할 때까지 리소스 로드를 지연한다.
- eager: loading 속성의 기본값으로, 페이지 내 위치에 관계없이 이미지가 로드된다.
설정이 간단하다는 장점이 있지만, 오래된 브라우저는 지원하지 않는다. 크로미움 브라우저의 경우 이미지 타입과 사용자의 네트워크 환경에 따라 로드할 기준점을 (threshold) 판단한다. (참고 문서) 이는 기준점 내의 뷰포트 하단 이미지들까지 미리 요청하게 해, 유저가 스크롤을 내리며 하단 이미지를 탐색할 때 지연없이 바로 표시 되게 한다.
요청의 우선순위 높이기 - Fetch Priority
fetchPriority는 요청들 중에서 어떤 요청의 우선순위가 높은지 지정할 수 있도록 돕는다. fetchPriority 속성을 이용하여 브라우저에 어떤 이미지가 중요하고 먼저 로드되었으면 하는지 힌트를 줄 수 있다.
<img src="image.png" fetchPriority="high" alt="…" width="200" height="200">
fetchPriority 속성에는 high, low, auto의 세 가지 값이 있다.
- high: 브라우저에 해당 리소스가 중요하다고 알려주어 우선적으로 로딩을 수행한다.
- low: 반대로 덜 중요한 이미지의 경우 로딩 우선순위를 낮추도록 설정한다.
- auto: 브라우저가 우선순위를 자동으로 결정하게 한다.
직접 설정해 확인했을 때 initial priority가 '높음'으로 바뀐 것을 확인할 수 있었다. 또한 Duration 부분을 확인해보면 요청을 보내기까지 대기하는 시간이 줄어들었고, 실제 다운로드하는 시간도 짧아진 것을 확인할 수 있었다.
마무리하며
중요한 이미지를 빠르게 로드하기 위한 세 가지 방법에 대해 살펴보았다. 세 가지 방법은 상황과 목적에 맞게 선택해 사용하는 것이 좋다. 우선 현재 사이트에서 히어로 이미지같이 중요한 이미지의 로드 속도가 느린지 확인하고 느린 원인들을 찾는 것이 우선일 것이다.
내가 작업하는 웹사이트는 React js로 클라이언트 사이드 렌더링을 하는 상황이었고, LCP 요소의 이미지가 동적으로 설정되고 있었다. 동적으로 preload를 적용하는 것은 효과가 크지 않다고 판단되었다. 그보다 다양한 이미지들을 동일한 우선순위로 동시에 요청하는 것이 이미지 로드를 늦추는 원인이라 생각했고, loading 속성을 이용한 레이지 로딩과 fetchPriority를 이용해 최적화를 진행했다.
참고 문서
https://web.dev/articles/browser-level-image-lazy-loading?hl=ko
웹용 브라우저 수준 이미지 지연 로드 | Articles | web.dev
이 게시물에서는 로드 속성 및 이 속성을 사용하여 이미지 로드를 제어하는 방법을 다룹니다.
web.dev
https://web.dev/articles/fetch-priority
Fetch Priority API로 리소스 로드 최적화 | Articles | web.dev
Fetch Priority API는 브라우저에 대한 리소스의 상대적 우선순위를 나타냅니다. 로드를 최적화하고 코어 웹 바이탈을 개선할 수 있습니다.
web.dev