크롬 네이티브 레이지 로딩

레이지 로딩이란?

좋은 기회로 2019년 구글I/O에 참석했다. 웹 기술 세션 중에는 크게 눈에 띄는 세션은 없었지만, 일부 세션에서 소개된 웹과 관련 기술 몇 가지는 흥미로웠다. Native Lazy Loading, Portals, Duplex, Rich Results 정도가 나의 관심을 끌었다. 그중 키노트에서 시작해 몇 개의 세션에서 두루두루 언급한 네이티브 레이지 로딩이 제일 기대됐다.

관련 세션

레이지 로딩, 특히 이미지 레이지 로딩은 새로운 기술은 아니다. 기존 브라우저는 웹페이지를 불러올 때 초기부터 전체 영역에 해당하는 이미지들을 동시에 모두 내려받는다. 서비스의 사용자는 웹페이지의 모든 이미지를 보지 못한 채 다른 웹페이지로 이동할 가능성이 있지만, 브라우저는 항상 모든 이미지를 미리 내려받는 낭비를 하는 것이다. 이미지 레이지 로딩은 초기 페이지 로딩에서 모든 이미지를 내려받지 않는다. 초기에는 브라우저 뷰포트에 보이는 영역의 이미지만 내려받고 나머지 이미지는 필요한 상황이거나 가능성이 큰 상황을 휴리스틱(heuristics)을 이용해 판단하고 이미지를 내려받는다. 즉 유저의 스크롤이나 기타 환경 요인들을 판단해 이미지를 선택적으로 내려받는다.

레이지 로딩 뷰포트의 이미지만 로드

레이지 로딩을 적용하면 불필요한 네트워크 비용을 줄일 뿐 아니라 성능, 메모리, 사용성 모든 면에서 유리해진다. 기존에는 레이지 로딩을 자바스크립트로 직접 구현하거나 라이브러리를 사용했다. 브라우저의 네이티브로 지원되는 레이지 로딩은 이미지를 내려받는 시점의 판단을 브라우저 내부에서 결정하기 때문에 자바스크립트보다는 많은 정보에 접근할 수 있을 것이고 더욱 정교한 휴리스틱을 사용할 것으로 예상된다. 반면 이런 판단에 개입할 수 있는 옵션은 제공되지 않을 것으로 보인다. 크롬은 75 버전부터 iframeimg 의 레이지 로딩을 네이티브로 지원할 예정이다.

새로운 속성 loading

공식 레이지 로드 디자인 문서에 따르면 레이지로딩은 <img><iframe> 엘리멘트에 추가되는 새로운 속성 loading 으로 설정할 수 있다고 한다.

<img src="cat.jpg" loading="lazy" />
<iframe src="some.html" loading="lazy"></iframe>

loading 속성으로 lazy 값을 주면 해당 이미지나 아이프레임은 레이지 로딩된다.

<img src="cat.jpg" loading="eager" />
<iframe src="some.html" loading="eager"></iframe>

eager 값은 의도적으로 레이지 로딩을 사용하지 않고 기존 브라우저의 동작과 동일하게 페이지 로딩 시 이미지를 내려받는다. 상황에 따라서는 레이지 로딩이 필요하지 않을 수도 있다. 서비스 사용성에 레이지 로딩이 방해된다면 eager 옵션을 설정한다.

<img src="cat.jpg" loading="auto" />
<img src="cat.jpg" />

autoloading 속성의 디폴트 값으로 따로 속성을 지정하지 않으면 적용되는 값이다. 브라우저에게 레이지 로딩을 할지 말지에 대한 결정을 맡긴다.

크롬은 세계에서 제일 많이 사용하고 있는 브라우저가 된 지 오래고 한국에서도 현재 53% 이상의 사용률로 제일 많이 사용되고 있다.

브라우저 사용율

이 53%의 사용자를 고려해 미리 테스트해볼 필요가 있다. 특히 이미지에 민감한 서비스라면 정식 버전에 포함되기 전에 반드시 미리 사용성을 테스트해 보고 서비스에 맞는 적절한 대응이 필요하다. 보통은 문제 없을 것으로 예상되지만, 디폴트가 auto 값이라는 점은 사용성에 의도치 않은 문제를 발생시킬 수 있다. 아직 레이지 로딩의 도입을 고려할 수 없는 서비스라면 적어도 이미지마다 loading 의 값을 eager 로 적용해 기존의 동작과 동일하게 유지할 필요가 있지 않나 생각한다. 물론 auto 가 전혀 문제 없을 수도 있다.

기능 탐지 및 폴백

LazyLoad Explainer 문서를 살펴보면 레이지 로드를 지원하는 브라우저를 탐지하는 방법을 알 수 있다. 다른 기능 탐지와 비슷한데 이미지 엘리먼트의 인터페이스 HTMLImageElement의 프로토타입에 loading 프로퍼티가 존재하는지 판단한다.

if ('loading' in HTMLImageElement.prototype) alert("네이티브 레이지 로딩 지원함"); else alert("지원 안함");

loading 속성을 적용해 간단히 사용할 수 있고 서비스에 악영향을 줄 가능성이 적기 때문에 기존에 레이지 로딩을 사용하지 않던 서비스도 크롬에서는 레이지 로딩을 사용하고 다른 브라우저에서는 무시하더라도 충분히 효과는 있겠지만 레이지 로딩을 모든 브라우저에서 제공하고자 한다면 폴백으로 다른 라이브러리를 고려해볼 수 있다.(물론 직접 만들 수도 있다)

크로스브라우징

구글 I/O의 “Speed at Scale” 세션에서는 폴백으로 lazysizes라는 라이브러리를 사용하는 예제 코드를 공개했다. 이미지의 코드는 가독성이 떨어져 Addy Osmani의 블로그에서 동일한 코드를 복사해서 옮겨 왔다.

<!-- Let's load this in-viewport image normally -->
<img src="hero.jpg" alt=".."/>

<!-- Let's lazy-load the rest of these images -->
<img data-src="unicorn.jpg" loading="lazy" alt=".." class="lazyload"/>
<img data-src="cats.jpg" loading="lazy" alt=".." class="lazyload"/>
<img data-src="dogs.jpg" loading="lazy" alt=".." class="lazyload"/>

<script>
  if ('loading' in HTMLImageElement.prototype) {
    const images = document.querySelectorAll("img.lazyload");  
    images.forEach(img => {
      img.src = img.dataset.src;
    });
  } else {
    let script = document.createElement("script");
    script.async = true;
    script.src = "https://cdnjs.cloudflare.com/ajax/libs/lazysizes/4.1.8/lazysizes.min.js";
    document.body.appendChild(script);
  }
</script>

lazysizes 와 같은 라이브러리를 사용해보진 않았지만, 이미지 레이지 로딩 구현 코드들이 다 비슷하기 때문에 구현 내용을 추측할 수 있다. 초기에는 모든 <img> 엘리먼트에 플레이스 홀더 이미지를 노출하고 data-src 경로의 이미지를 적절한 상황에 내려받고 완료되면 이미지 엘리먼트의 소스로 변경하는 형태로 구현되었을 것이다. 폴백 예제의 구현 내용을 보면 초기에는 lazysizes 를 사용하는 코드로 작업하고 기능탐지로 네이티브 레이지 로딩을 사용할 수 있다면 lazysizes 에서 필요한 data-src 를 모두 src 로 바꿔 네이티브 레이지 로딩을 사용하도록 엘리먼트를 변경하고 있다.

정리

귀국 후 Addy Osmani의 블로그의 하단 내용을 따라서 크롬 카나리버전에서 테스트해봤다. 기능 탐지도 되고 Image 객체의 loading 값까지 확인할 수 있었지만, 정상적으로 레이지 로딩이 되지 않고 웹페이지 로딩 초기부터 모든 이미지를 내려받고 있다. 아직 개발 중인 기능이기에 정식 버전이나 더 나은 카나리버전에서는 정상 동작할 것으로 기대한다. 테스트해본 카나리버전은 76.0.3799.0 이다.

네이티브 레이지 로딩은 Webkit 엔진 개발자들도 긍정적으로 검토하고 있다는 카더라가 있고 파이어폭스는 곧 크롬과 동일한 스펙으로 적용될 예정이라고 ZDNET 의 기사로 올라왔다. 마이크로소프트의 Edge도 크로미엄 기반으로 개발되고 있으니 크롬에서 시작한 스펙이 자연스럽게 표준이 되고 있는 게 현실인 것 같다. 물론 좋은 기능이고 충분히 표준 스펙으로 고려할만한 기능이지만 작년에 읽었던 “Chrome is turning into the new Internet Explorer 6” 이란 아티클이 떠올랐다. 뭐 어떻게 되었던 좋은 스펙이 많이 개발되서 웹의 가능성이 더 열리고 나의 밥그릇의 가능성도 더 커졌으면 좋겠다.