IntersectionObserver to create a lazy load Images with data-srcset and imagekit.io
Asked Answered
C

2

0

I am using IntersectionObserver.js with data-srcset to create a lazy load but images aren't displaying correctly as per the resolution, every time the browser chooses the largest image... in this case it is the image with 450 width, ignoring the others width's (100px, 200px, 300px, 400px).

Here is the JS code doing used to lazy-load:

const images = document.querySelectorAll('img[data-src]');
const config = {
  rootMargin: '50px 0px',
  threshold: 0.01
};

let observer;

if ('IntersectionObserver' in window) {
  observer = new IntersectionObserver(onChange, config);
  images.forEach(img => observer.observe(img));
} else {
  console.log('%cIntersection Observers not supported', 'color: red');
  images.forEach(image => loadImage(image));
}

const loadImage = image => {
  image.classList.add('fade-in');
  image.src = image.dataset.src;
  image.srcset = image.dataset.srcset;
}

function onChange(changes, observer) {
  changes.forEach(change => {
    if (change.intersectionRatio > 0) {
      // Stop watching and load the image
      loadImage(change.target);
      observer.unobserve(change.target);
    }
    
  });
}

And here is the HTML code used (it's an article category page):

<img class="img-fluid"
src="data:image/webp;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
data-src="https://ik.imagekit.io/amalgama/usuarios/administradores/admin/artigos/thumb/7-passos-para-sair-das-dividas-e-se-tornar-um-empreendedor.webp?tr=w-100"
alt="bla bla bla"
title="bla bla bla"
data-srcset="https://ik.imagekit.io/amalgama/usuarios/administradores/admin/artigos/thumb/7-passos-para-sair-das-dividas-e-se-tornar-um-empreendedor.webp?tr=w-100 100w,
https://ik.imagekit.io/amalgama/usuarios/administradores/admin/artigos/thumb/7-passos-para-sair-das-dividas-e-se-tornar-um-empreendedor.webp?tr=w-200 200w,
https://ik.imagekit.io/amalgama/usuarios/administradores/admin/artigos/thumb/7-passos-para-sair-das-dividas-e-se-tornar-um-empreendedor.webp?tr=w-300 300w,
https://ik.imagekit.io/amalgama/usuarios/administradores/admin/artigos/thumb/7-passos-para-sair-das-dividas-e-se-tornar-um-empreendedor.webp?tr=w-400 400w,
https://ik.imagekit.io/amalgama/usuarios/administradores/admin/artigos/thumb/7-passos-para-sair-das-dividas-e-se-tornar-um-empreendedor.webp?tr=w-450 450w"
width="450px"
height="278px">

You can see the demo page running at URL below:

demo link

Well, do you know why the other sizes aren't displaying? Only the largest image in every screen ;(

Cullen answered 23/1, 2023 at 1:4 Comment(0)
C
0

I forgot to post the solution before, but here we go, after many tests I finally found a way to work with data-srcset, lazyload, imagekit and declaring height and width to optimize google page insight. It works with desktop and mobile, with all types of device pixels ratios... Hope it helps someone :)

The media size needs to be the double (don't ask me why lol)

Demo production link.

CODE

<script src="https://cdn.jsdelivr.net/npm/[email protected]/intersection-observer.min.js"></script>

Javascript:

const config = {
  rootMargin: '50px 0px',
  threshold: 0.01
};

if ('IntersectionObserver' in window) {
  LazyLoad();
} else {
  ShowAllImages();
}

function LazyLoad(){
  let observer;
  let images = document.querySelectorAll('img[data-src]');
  observer = new IntersectionObserver(onChange, config);
  images.forEach(img => observer.observe(img));
}

function ShowAllImages() {
  images.forEach(image => loadImage(image));
}

const loadImage = image => {
  image.classList.add('fade-in');
  image.src = image.dataset.src;
  image.srcset = image.dataset.srcset;
}

function onChange(changes, observer) {
  changes.forEach(change => {
    if (change.intersectionRatio > 0) {
      // Stop watching and load the image
      loadImage(change.target);
      observer.unobserve(change.target);
    }
    
  });
}

HTML:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<figure>
    <img 
    width="950" height="950"
    src="data:image/webp;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
    data-src="http://placehold.it/950x950" 
    sizes="(max-width: 125px), 
    (max-width: 150px), 
    (max-width: 175px), 
    (max-width: 200px), 
    (max-width: 225px), 
    (max-width: 250px), 
    (max-width: 275px), 
    (max-width: 300px), 
    (max-width: 325px), 
    (max-width: 350px), 
    (max-width: 375px), 
    (max-width: 400px), 
    (max-width: 425px), 
    (max-width: 450px), 
    (max-width: 475px), 
    (-webkit-min-device-pixel-ratio: 1.1) AND (-webkit-max-device-pixel-ratio: 1.5) 80.5vw, 
    (-webkit-min-device-pixel-ratio: 1.6) AND (-webkit-max-device-pixel-ratio: 2) 57.5vw, 
    (-webkit-min-device-pixel-ratio: 2.1) AND (-webkit-max-device-pixel-ratio: 2.5) 42.5vw, 
    (-webkit-min-device-pixel-ratio: 2.6) AND (-webkit-max-device-pixel-ratio: 3) 39.5vw, 
    (-webkit-min-device-pixel-ratio: 3.1) AND (-webkit-max-device-pixel-ratio: 3.5) 32.5vw, 
    (-webkit-min-device-pixel-ratio: 3.6) AND (-webkit-max-device-pixel-ratio: 4) 28.5vw" 
    data-srcset="http://placehold.it/250x250 250w, 
    http://placehold.it/300x300 300w, 
    http://placehold.it/350x350 350w, 
    http://placehold.it/400x400 400w, 
    http://placehold.it/450x450 450w, 
    http://placehold.it/500x500 500w, 
    http://placehold.it/550x550 550w, 
    http://placehold.it/600x600 600w, 
    http://placehold.it/650x650 650w, 
    http://placehold.it/700x700 700w, 
    http://placehold.it/750x750 750w, 
    http://placehold.it/800x800 800w, 
    http://placehold.it/850x850 850w, 
    http://placehold.it/900x900 900w, 
    http://placehold.it/950x950 950w" 
    >
</figure>
Cullen answered 2/7, 2023 at 5:30 Comment(0)
C
0

I think your lazy loading may be creating these issues. If you check where your image requests originate you can see it's from the loadImage function in universal.js that directly sets the src attribute of the image. Maybe you could try the native browser lazy loading and skip the intersection observer shenanigans: https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading

Coplin answered 25/1, 2023 at 20:27 Comment(1)
So I cant use intersection observer with data-srcset atribute?Cullen
C
0

I forgot to post the solution before, but here we go, after many tests I finally found a way to work with data-srcset, lazyload, imagekit and declaring height and width to optimize google page insight. It works with desktop and mobile, with all types of device pixels ratios... Hope it helps someone :)

The media size needs to be the double (don't ask me why lol)

Demo production link.

CODE

<script src="https://cdn.jsdelivr.net/npm/[email protected]/intersection-observer.min.js"></script>

Javascript:

const config = {
  rootMargin: '50px 0px',
  threshold: 0.01
};

if ('IntersectionObserver' in window) {
  LazyLoad();
} else {
  ShowAllImages();
}

function LazyLoad(){
  let observer;
  let images = document.querySelectorAll('img[data-src]');
  observer = new IntersectionObserver(onChange, config);
  images.forEach(img => observer.observe(img));
}

function ShowAllImages() {
  images.forEach(image => loadImage(image));
}

const loadImage = image => {
  image.classList.add('fade-in');
  image.src = image.dataset.src;
  image.srcset = image.dataset.srcset;
}

function onChange(changes, observer) {
  changes.forEach(change => {
    if (change.intersectionRatio > 0) {
      // Stop watching and load the image
      loadImage(change.target);
      observer.unobserve(change.target);
    }
    
  });
}

HTML:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<figure>
    <img 
    width="950" height="950"
    src="data:image/webp;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
    data-src="http://placehold.it/950x950" 
    sizes="(max-width: 125px), 
    (max-width: 150px), 
    (max-width: 175px), 
    (max-width: 200px), 
    (max-width: 225px), 
    (max-width: 250px), 
    (max-width: 275px), 
    (max-width: 300px), 
    (max-width: 325px), 
    (max-width: 350px), 
    (max-width: 375px), 
    (max-width: 400px), 
    (max-width: 425px), 
    (max-width: 450px), 
    (max-width: 475px), 
    (-webkit-min-device-pixel-ratio: 1.1) AND (-webkit-max-device-pixel-ratio: 1.5) 80.5vw, 
    (-webkit-min-device-pixel-ratio: 1.6) AND (-webkit-max-device-pixel-ratio: 2) 57.5vw, 
    (-webkit-min-device-pixel-ratio: 2.1) AND (-webkit-max-device-pixel-ratio: 2.5) 42.5vw, 
    (-webkit-min-device-pixel-ratio: 2.6) AND (-webkit-max-device-pixel-ratio: 3) 39.5vw, 
    (-webkit-min-device-pixel-ratio: 3.1) AND (-webkit-max-device-pixel-ratio: 3.5) 32.5vw, 
    (-webkit-min-device-pixel-ratio: 3.6) AND (-webkit-max-device-pixel-ratio: 4) 28.5vw" 
    data-srcset="http://placehold.it/250x250 250w, 
    http://placehold.it/300x300 300w, 
    http://placehold.it/350x350 350w, 
    http://placehold.it/400x400 400w, 
    http://placehold.it/450x450 450w, 
    http://placehold.it/500x500 500w, 
    http://placehold.it/550x550 550w, 
    http://placehold.it/600x600 600w, 
    http://placehold.it/650x650 650w, 
    http://placehold.it/700x700 700w, 
    http://placehold.it/750x750 750w, 
    http://placehold.it/800x800 800w, 
    http://placehold.it/850x850 850w, 
    http://placehold.it/900x900 900w, 
    http://placehold.it/950x950 950w" 
    >
</figure>
Cullen answered 2/7, 2023 at 5:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.