본문 바로가기
JavaScript

HTML - 이미지 태그에 lazy loading 적용하기

by 새발개발JA 2024. 12. 27.
반응형

 

 

웹의 화면을 그리는 로딩(렌더)시간은 짧으면 짧을 수록 좋다.

결국 리소스를 서버에서 받아와 그리는 작업이기 때문에 마치 전투와 같이 어떤 병력을 선발대와 후발대로 배치하느냐의 전략과도 같다고 생각한다. 날쌔고 빠른 놈은 선발대로 보내고, 무겁고 느린놈은 후발대로 보내는 경우, 리소스 배치도 이와 비슷하다고 생각한다.

웹 페이지 로딩시에 텍스트나 작은 섬네일처럼 무게가 가벼운 친구들은 그대로 보여주지만 스크롤을 내려야 만날 수 있는 애들은 내릴때쯤 느긋하게 보여주는 것도 방법이다.

 

이를 위해 여러 프레임워크의 라이브러리나 바닐라로 구현도 가능하겠지만, 이 포스팅에서는 브라우저 레벨에서의 attribute 로서의 lazy 에 대해서 최대한 심플하게 설명하고자 한다. 해외 블로그의 브라우저 로드에 관한 포스팅도 중간중간 번역해보았다.

 

웹용 브라우저 수준 이미지 지연 로드  |  Articles  |  web.dev

이 게시물에서는 로드 속성 및 이 속성을 사용하여 이미지 로드를 제어하는 방법을 다룹니다.

web.dev

 


HTML - 이미지 태그에 lazy loading 적용하기

 

Why browser-level lazy loading?

브라우저 레벨의 레이지 로딩이 왜 필요한 걸까? 대부분의 웹사이트에서는 이미지 다운받는데 걸리는 시간이 상당하다. 그래서 레이지로딩을 구현하기 위해 Intersection Observer API 를 사용하거나 scroll, resize, orientationchange 등의 내장 api 를 사용하거나 서드파티 라이브러리를 사용했다. 이들의 공통점은 뷰포트에 보이지 않는 부분들이 보여질때 이를 감지하고 로딩할 수 있도록 도와주는 native 기능이다. 

 

하지만...! (두둥) 브라우저에서 지원하는 레이지 로드 기능으로 인해 부가적인 노력을 기울일 필요가 없게 되었다. 특히..! 자바 스크립트 기능을 비활성화한 상태에서도 에러없는 이미지 로딩이 동작한다. 다만 자바스크립트 기능을 켜야만 레이지로딩기능이 제대로 실행된다.

 

The loading attribute

레이지 로드를 위해서는 <img> 태그 속성 중 하나인 loading 을 넣어주어야 한다.

크롬은 뷰포트에서 이미지 위치에 따라서 로드하는 우선 순위가 달라진다. 이미지가 뷰포트를 벗어나 위치한다면 우선순위가 낮아지게 되지만 여전히 페이지가 로드될 때 데이터 fetch 가 이루어진다.

loading 의 속성은 lazy 와 eager 이 있다.

  • lazy: Defer loading of the resource until it reaches a calculated distance from the viewport. (레이지 로드용)
  • eager: Default loading behavior of the browser, which is the same as not including the attribute and means the image is loaded regardless of where it's located on the page. (일반 로드용)

 

Give your images dimension attributes

이미지 사이즈를 넣어줘야 한다. 결국 브라우저가 로드할때 미리 이미지 자리 확보를 하지 않으면 로드 후 순간적으로 이미지가 타탁하고 나타나는 layout shifts 현상이 발생한다. 식당 예약을 할때 인원수와 메뉴를 미리 주문하는 것처럼 <img widht="" height="" /> 의 속성을 넣어준다면, 브라우저는 미리 공간 확보를 해놓을 수가 있다. 이부분은 레이지 로딩과 상관없이 다 넣는 것이 권장된다.

 

만약 동적으로 받아와 이미지 사이즈를 모른다면, 대부분의 경우 그래도 레이지 로딩을 보장한다. 하지만 몇몇 예외적인 케이스는 발생할 수 있다. 예를 들어 이미지 갤러리처럼 브라우저가 이미지들이 모여있어 브라우저가 뷰포트에 있다고 판단하는 경우 한꺼번에 로드를 하기 때문에 로딩시간이 걸릴 수도 있다.

 

img 태그 단독 사용시

<img src="이미지 소스" loading="lazy" width="100" height="50"/>

 

 

picture 태그 사용시

// picture 태그를 사용할 때 실질적으로 동작하는 것은 img 라서 source 에는 적용하지 않아도 된다
// 다만 width / height 속성은 기본적으로 픽셀이 기본값이며 퍼센트는 적용되지 않는다
<picture>
  <source media="(max-width: 745px)" srcset="모바일용 이미지 주소" />
  <source media="(max-width: 1024px)" srcset="태블릿용 이미지 주소" />
  <img src="기본 이미지 주소" loading="lazy" width="100" height="50"/>
</picture>

 

 

Relationship between the loading attribute and fetch priority

여기서부터는 좀더 심화적으로 생각을 해보게되는 부분인데, 데이터 fetch 와 lazy load 의 관계에 대한 고민을 해보게 된다.

 

loading="eager"

"eager" 를 넣은 이미지는 뷰포트 바깥에 있어도 첫 렌더에 한꺼번에 로드가 된다. loading 속성이 없는 이미지보다 빠르게 로딩되지는 않는다. 그래서 만약에 중요한 이미지를 빨리 가져오고 싶다면, fetchpriority="high" 을 추가해주면 된다.

 

loading="lazy" 

만약에 <img loading="lazy" 와 fetchpriority="high" > 인 이미지가 뷰포트에서 벗어나 있다면, 뷰포트에 들어오는 순간 높은 우선순위를 가지고 이미지를 불러올 것이다. 근데 요 속성 두개를 한꺼번에 쓰는 건 꼭 필요하진 않은 것이 브라우저가 알아서 우선순위로 로드 해주기 때문이다.

 

 

How to use in React.js and Next.js

이 파트는 개인적으로 한번더 복기해보고자 정리해보았다. 가장 많이 사용되는 리액트와 넥스트의 경우, 어떻게 사용되고 있는지 알아보자

 

리액트에서는 HTML 속성 그대로 loading="lazy" 를 추가하면 된다

function App() {
  return (
    <img
      src="example.jpg"
      alt="Example Image"
      loading="lazy" // 브라우저의 lazy loading 활성화
    />
  );
}

 

 

넥스트에서는 next/image 컴포넌트가 있어 레이지로드 핸들링이 편해졌다

이 친구는 lazy loading뿐만 아니라 이미지 최적화, 반응형 크기 조정, 포맷 변환(WebP 등)을 자동으로 처리해준다 👍

<Image 
    src="/example.jpg" 
    alt="Example Image" 
    width={800} 
    height={600} 
    layout="responsive" // 이미지크기 반응형 설정 및 최적화된 크기로 로드
    loading="lazy" // 즉시 로드일 땐 "eager"
    priority // 중요 이미지로 설정
/>

 

반응형

댓글