지연 로드 권장사항

이미지 및 동영상 지연 로드에는 긍정적이고 측정 가능한 성능 이점이 있지만, 가볍게 여겨서는 안 되는 작업입니다. 잘못하면 의도하지 않은 결과가 발생할 수 있습니다. 따라서 다음 사항에 유의해야 합니다.

화면 접기에 주의하기

자바스크립트를 사용하여 페이지의 모든 미디어 리소스를 지연 로드하고 싶을 수 있지만, 이러한 유혹을 참아야 합니다. 스크롤 없이 볼 수 있는 부분에 있는 항목은 지연 로드하면 안 됩니다. 이러한 리소스는 중요한 애셋으로 간주되므로 정상적으로 로드되어야 합니다.

지연 로드는 스크립트 로드가 완료되고 실행을 시작할 때 DOM이 대화형이 될 때까지 리소스 로드를 지연시킵니다. 스크롤해야 볼 수 있는 부분에 있는 이미지의 경우에는 문제가 되지 않지만 스크롤 없이 볼 수 있는 부분에 있는 중요한 리소스는 최대한 빨리 표시되도록 표준 <img> 요소로 로드해야 합니다.

물론 최근에는 다양한 크기의 여러 화면에서 웹사이트를 보는 경우 접점이 어디인지 불분명합니다. 노트북에서 스크롤 없이 볼 수 있는 부분이 휴대기기에서는 스크롤 없이 볼 수 있는 부분의 아래에 놓일 수도 있습니다. 모든 상황에서 이 문제를 최적으로 해결하는 완벽한 조언은 없습니다 페이지의 중요 애셋 인벤토리를 실행하고 일반적인 방식으로 이러한 이미지를 로드해야 합니다.

또한 지연 로드를 트리거하는 기준점으로 접힘 선을 너무 엄격하게 지정하지 않는 것이 좋습니다. 사용자가 표시 영역으로 스크롤하기 한참 전에 이미지가 로드되기 시작하도록 스크롤해야 볼 수 있는 부분의 어느 정도 거리에 완충 영역을 설정하는 것이 더 적합할 수 있습니다. 예를 들어 Intersection Observer API를 사용하면 새 IntersectionObserver 인스턴스를 만들 때 옵션 객체에 rootMargin 속성을 지정할 수 있습니다. 이렇게 하면 요소에 효과적으로 버퍼를 제공하여 요소가 표시 영역에 도달하기 전에 지연 로드 동작을 트리거합니다.

let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
  // lazy-loading image code goes here
}, {
  rootMargin: "0px 0px 256px 0px"
});

rootMargin 값이 CSS margin 속성에 지정한 값과 비슷해 보이면 맞기 때문입니다. 이 경우 관찰된 요소 (기본적으로 브라우저 표시 영역이지만 root 속성을 사용하여 특정 요소로 변경할 수 있음)의 하단 여백이 256픽셀로 넓어집니다. 즉, 이미지 요소가 표시 영역의 256픽셀 이내에 있을 때 콜백 함수가 실행되며 사용자가 실제로 이미지를 보기 전에 이미지가 로드됩니다.

Intersection Observe를 지원하지 않는 브라우저에서 이와 같은 효과를 얻으려면 스크롤 이벤트 처리 코드를 사용하고 버퍼를 포함하도록 getBoundingClientRect 검사를 조정하세요.

레이아웃 이동 및 자리표시자

자리표시자를 사용하지 않으면 미디어 지연 로드로 인해 레이아웃이 이동할 수 있습니다. 이러한 변경사항은 사용자에게 혼란을 줄 수 있으며, 시스템 리소스를 소비하고 버벅거림을 유발하는 값비싼 DOM 레이아웃 작업을 트리거할 수 있습니다. 최소한 타겟 이미지와 동일한 크기를 차지하는 단색 자리표시자 또는 로드되기 전에 미디어 항목의 콘텐츠를 암시하는 LQIPSQIP와 같은 기법을 사용하는 것이 좋습니다.

<img> 태그의 경우 속성이 최종 이미지 URL로 업데이트될 때까지 src은 처음에 자리표시자를 가리켜야 합니다. <video> 요소에서 poster 속성을 사용하여 자리표시자 이미지를 가리킵니다. 또한 <img><video> 태그 모두에 widthheight 속성을 사용합니다. 이렇게 하면 자리표시자에서 최종 이미지로 전환해도 미디어가 로드될 때 렌더링된 요소 크기가 변경되지 않습니다.

이미지 디코딩 지연

JavaScript로 큰 이미지를 로드하고 DOM에 드롭하면 기본 스레드가 묶여서 사용자 인터페이스가 디코딩이 진행되는 동안 잠시 응답하지 않을 수 있습니다. DOM에 삽입하기 전에 decode 메서드를 사용하여 이미지를 비동기적으로 디코딩하면 이러한 종류의 버벅거림을 줄일 수 있지만 주의할 점은 아직 모든 곳에서 사용할 수 없으며 지연 로드 로직이 복잡해진다는 점입니다. 사용하려면 확인해야 합니다. 다음은 대체와 함께 Image.decode()를 사용하는 방법을 보여줍니다.

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

if ("decode" in newImage) {
  // Fancy decoding logic
  newImage.decode().then(function() {
    imageContainer.appendChild(newImage);
  });
} else {
  // Regular image load
  imageContainer.appendChild(newImage);
}

이 CodePen 링크에서 이 예와 유사한 코드를 실제로 확인합니다. 대부분의 이미지가 상당히 작으면 별다른 이점은 없을 수 있지만 큰 이미지를 지연 로드하고 DOM에 삽입할 때 발생하는 버벅거림을 줄이는 데 도움이 될 수 있습니다.

콘텐츠가 로드되지 않을 때

미디어 리소스가 여러 가지 이유로 로드되지 않고 오류가 발생하는 경우가 있습니다. 언제 이런 일이 일어날까요? 경우에 따라 다르지만 다음과 같은 가상의 시나리오가 있습니다. 짧은 시간 (예: 5분) 동안 HTML 캐싱 정책을 사용 중이고 사용자가 사이트를 방문하거나 사용자가 오래된 탭을 장시간 (예: 몇 시간) 열어 둔 후 콘텐츠를 읽기 위해 다시 돌아오는 경우입니다. 이 프로세스의 특정 시점에서 재배포가 발생합니다. 이 배포 중에 이미지 리소스의 이름이 해시 기반 버전 관리로 인해 변경되거나 완전히 삭제됩니다. 사용자가 이미지를 지연 로드할 때는 리소스를 사용할 수 없으므로 실패합니다.

이는 비교적 드물게 발생하지만 지연 로드가 실패할 경우에 대비한 백업 계획을 마련하는 것이 좋습니다. 이미지의 경우 이러한 솔루션은 다음과 같을 수 있습니다.

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

newImage.onerror = function(){
  // Decide what to do on error
};
newImage.onload = function(){
  // Load the image
};

오류 발생 시 수행할 작업은 애플리케이션에 따라 다릅니다. 예를 들어 이미지 자리표시자 영역을 사용자가 이미지를 다시 로드할 수 있는 버튼으로 바꾸거나 이미지 자리표시자 영역에 오류 메시지를 표시할 수 있습니다.

다른 시나리오도 발생할 수 있습니다. 무엇을 하든 오류가 발생했을 때 이를 사용자에게 알리고 문제가 발생했을 때 취해야 할 조치를 제공하는 것은 바람직하지 않습니다.

자바스크립트 사용 가능 여부

JavaScript를 항상 사용할 수 있다고 가정해서는 안 됩니다. 이미지를 지연 로드하려는 경우 자바스크립트를 사용할 수 없을 때 이미지를 표시하는 <noscript> 마크업을 제공하는 것이 좋습니다. 가장 간단한 대체 예는 JavaScript가 사용 중지된 경우 <noscript> 요소를 사용하여 이미지를 제공하는 것입니다.

저는 이미지입니다.

JavaScript가 사용 중지되어 있으면 사용자에게 자리표시자 이미지와 <noscript> 요소에 포함된 이미지가 모두 표시됩니다. 이 문제를 해결하려면 다음과 같이 no-js 클래스를 <html> 태그에 배치합니다.

<html class="no-js">

그런 다음 JavaScript가 사용 설정된 경우 <html> 요소에서 no-js 클래스를 삭제하는 <link> 태그를 통해 스타일시트를 요청하기 전에 <head>에 인라인 스크립트 한 줄을 배치합니다.

<script>document.documentElement.classList.remove("no-js");</script>

마지막으로 JavaScript를 사용할 수 없을 때 몇 가지 CSS를 사용하여 지연 클래스가 있는 요소를 숨깁니다.

.no-js .lazy {
  display: none;
}

이렇게 하면 자리표시자 이미지가 로드되는 것을 막을 수는 없지만 결과는 더 바람직합니다. JavaScript를 사용 중지한 사용자는 자리표시자 이미지보다 더 나은 결과를 얻게 됩니다. 이는 자리표시자보다 우수하고 의미 있는 콘텐츠가 전혀 없습니다.