Author: Mai Le

Source: Hang Seng LIGHT Cloud Community

Image delay loading

For a better performance experience, resource compression and proper file format selection are not enough. We also need to optimize the resource loading process.

What is lazy loading?

The following figure shows the home page of Jingdong Mall on the mobile phone. When the element does not slide into the line of sight, the image SRC attribute places a small image, while the init_src attribute places the real image. As long as the element slides into the line of sight, the init_src attribute is assigned to SRC to load the real image. This is a simple image lazy loading process.

Traditional mode lazy loading

Is the way of event monitoring, by listening to the scroll event and resize event, and in the event callback function to judge whether the picture needs to be lazy loading into the window area.

We only need to focus on three properties.

  • Class property, which is later used in JavaScript to select the < img > tag that needs lazy loading processing.
  • SRC attribute, placeholder image before loading, can be Base64 image or low resolution image.
  • The data-src attribute, which is used to save the external URL of the image.

There are several such images to load in the add page. Add the lazy loading logic to the DOMContentLoaded event of the document, first fetch all < img > tags with the class attribute named lazy, and temporarily store these tags in an array named lazyImages. Represents a collection of images that need lazy loading but have not yet been loaded. When an image is loaded, it is removed from the lazyImages array until the lazyImages array is empty, indicating that all images pending lazy loading have been loaded, then the page scrolling event can be removed.

The getBoundingClientRect () function is used to get the relative positions of the elements.

        rectObject = object.getBoundingClientRect();
Copy the code

Rectobject. top: The distance from the top of the element to the top of the window;

Rectobject. right: the distance from the right side of the element to the left side of the window;

Rectobject. bottom: Distance from the bottom of the element to the top of the window;

Rectobject. left: the distance between the left side of the element and the left side of the window;

For scrolling up and down pages, the method of determining whether an image element is present in the screen window is obvious. If the top value of the element’s upper edge from the top of the screen window is less than the window’s height, window.innerHeight, the preloaded event handling code is as follows:

document.addEventListener(DOMContentLoaded, function() {
      const imags = [].slice.call(document.querySelector('.lazy'))
      const active = false; // the limit function is frequently invoked
      function load() {
        if(active === false) {
          active = true
          setTimeout(() = > {
            imags.forEach((img) = > {
              const objPos = img.getBoundingClientRect();
              if(objPos.top <= window.innerHeight && objPos.bottom >=0&& img.display ! = ='done') {
                img.src = img.dataset.src;
                img.classList.remove('lazy')
                imags.filter((i) = >(i ! == img))if(imags.length === 0) {
                  document.removeEventListener('scroll', load)
                  window.removeEventListener('resize', load)
                  window.removeEventListener('orientationchange', load)
                }
  
              }
            })
            active = false
          }, 200)}}document.addEventListener('scroll', load)
      window.addEventListener('resize', load)
      window.addEventListener('orientationchange', load)

    })
Copy the code

The disadvantage of this method is the compatibility comparison number, but the disadvantage is that the frequent calculation will inevitably affect the performance and the code will be more cumbersome.

Implement lazy loading of images: Intersection Observer

The Intersection Observer API is already supported by most modern browsers. The callback function configured through the Intersection Observer API is triggered whenever a scrolling or window size change causes the target element to intersect with the device window or other specified element. Lazy-loaded logic is performed in the callback function. Will be more concise and efficient than the traditional way.

Simply put, the observer’s callback function is called when the visibility of the target element changes.

Callback typically fires twice. Once the target element has just entered the viewport (becoming visible), and once it has completely left the viewport (becoming invisible).

 document.addEventListener(DOMContentLoaded, function() {
        const imags = [].slice.call(document.querySelector('.lazy'))
        if(window.IntersectionObserver && window.IntersectionObserverEntry && window.IntersectionObserverEntry.prototype.intersectionRatio) {
          var lazyImgObserver = new IntersectionObserver((entries, observer) = > {
            entries.forEach((entry) = > {
              if(entry.isIntersecting) {
                var lazyImg = entry.target;
                lazyImg.src = lazyImg.dataset.src;
                lazyImg.classList.remove('lazy');
                lazyImgObserver.unobserve(lazyImg)
              }
            })
          })
          imags.forEach((img) = > {
            lazyImgObserver.observe(img)
          })
        }
   
      })
Copy the code

This method is easier and more intuitive to determine if an element is present in a window, and should be used as much as possible in practical development, but the problem is that not all browsers are compatible with it.

1. Check browser compatibility as fully as possible. Use this method for browsers that are compatible with the Intersection Observer API, and switch back to traditional implementations for those that are incompatible. (2) Use the corresponding compatible Polyfill plug-in, which is available under the official GitHub account of W3C.

Image lazy loading: CSS class name

In this way, images are loaded through the BACKground-image attribute of CSS. Instead of determining whether the < img > tag SRC attribute has a URL to request an image, images in CSS are loaded based on the browser’s analysis of the document.

  document.addEventListener(DOMContentLoaded, function() {
        const imags = [].slice.call(document.querySelector('.lazy'))
        if(window.IntersectionObserver && window.IntersectionObserverEntry && window.IntersectionObserverEntry.prototype.intersectionRatio) {
          var lazyImgObserver = new IntersectionObserver((entries, observer) = > {
            entries.forEach((entry) = > {
              if(entry.isIntersecting) {
                var lazyImg = entry.target;
                lazyImg.classList.add('visible');
                lazyImgObserver.unobserve(lazyImg)
              }
            })
          })
          imags.forEach((img) = > {
            lazyImgObserver.observe(img)
          })
        }
   
      })
Copy the code

This approach is limited to writing CSS styles in advance.

Native lazy loading support

In addition to implementing the lazy loading logic manually by developers, as of Chrome 75, lazy loading is now supported natively with the loading property of the < img > and < iframe > tags. The loading property has three values.

● Lazy: performs lazy loading. ● Eager: Load immediately. ● Auto: The browser decides whether to enable lazy loading.

Test: the image tag is img

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
  <! -- <script src="js/file2.js"></script> -->
  <! -- <script src="js/file3.js"></script> -->
  <! -- <link rel="stylesheet" href="css/index.css"> -->
  <style>
    img {
      width: 700px;
      height: 200px;
      display: block;
    }
  </style>
</head>
<body>

  
  
  <imgage loading="lazy" src='./image/home-1.png' alt="photo" />
  <imgage loading="lazy" src='./image/home-2.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-3.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-4.png' alt="photo" />
  <imgage loading="lazy" src='./image/home-5.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-6.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-7.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-8.png' alt="photo" />
  
  <imgage loading="lazy" src='./image/home-9.png' alt="photo" />
  <imgage loading="lazy" src='./image/home-10.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-11.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-12.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-13.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-14.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-15.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-16.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-17.png' alt="photo" />
  <imgage loading="lazy" src='./image/home-18.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-19.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-20.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-21.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-22.png' alt="photo" />
  
  <imgage loading="lazy" src='./image/home-23.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-24.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-25.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-26.png' alt="photo" />
  <imgage loading="lazy" src='./image/home-27.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-28.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-29.png' alt="photo" />

<imgage loading="lazy" src='./image/home-30.png' alt="photo" />



</body>
</html>
Copy the code

As can be seen, the number of loading for the first time is 13. Generally, the first screen can only put down about 4. After 13, the IMG will be automatically loaded when it scrolls into the line of sight.

The practical findings have the following characteristics:

  1. The amount of Lazy loading is related to the height of the screen, and the smaller the height, the less the load, but it is not linear.
  2. The number of Lazy loading is related to the network speed. The slower the network speed is, the more the load is, but the relationship is not linear.
  3. Without buffering, scrolling triggers the loading of a new image resource.
  4. Lazy loading is also triggered when the window resize changes, such as when the screen height increases from a small size.
  5. It is also possible to load images first in a Lazy load, such as when the page is loaded at a high scrolling height.

Several behavior characteristics associated with JavaScript:

  1. Check whether the browser supports native loading'loading' in XXXJudgment.
  2. Loading can be obtained by img.loading;
  3. Native loading do not write, do not access for example HTMLImageElement. The prototype. The loading complains Illegal invocation.
  4. If you want to use it, perform compatibility processing.