Is there way to lazy load images

I’d like to know if there are any implementations of lazy loading images out there, has anyone had success with the Intersection Observer API?

I haven’t used intersection observer but I have used resize observer. The wire up was a bit complicated and I would welcome suggestions for simplifying it:

  1. Put a special class name on the element I want to observe. Also include an event handler (see step 6).
  2. Use that class name to trigger a very quick CSS animation
  3. Have some JavaScript that watches for the end of the CSS animation
  4. (Curse and swear about the web being a pile of hacks. Optional.)
  5. When the animation end is detected, create an observer and have it watch the target element. On changes, have it send events to the target element.
  6. Receive notifications via the event handler

My first version of this used a port to trigger creation of the observer but that had trouble when the lifetime of the actual DOM element wasn’t clear because of virtual DOM reuse (or non-reuse) decisions. The CSS animation hack meant that the observer set up exactly matched with element creation.

Presumably the same techniques could work with the intersection observer API.

Mark

I think lazy-loaded images are a fantastic use case for a Custom Element!

There’s a few reasons for that:

  1. I find that images tend to be very “leaf” components in the applications and sites I build. When lazy-loading them as components, I care that they can handle loading and error states, but my “higher-level” code rarely cares about that. (Of course, if your application’s purpose is images, then that can change).

  2. The Observer APIs (which I love) can be annoying to set up through ports. But the main thing that I don’t like, is that from (1), my application wouldn’t use those events anyway.

  3. If / when browsers support native lazy-loading (not an easy task, but Chrome has lazyload in the works ), it will likely be an attribute on the HTML element. That to me is another data point that this concern is at the leaf node.

  4. I think that exposing events from the custom elements would be better if you happen to need those events.

Trying it out

Luke Westby has a talk that covers using Custom Elements in Elm. There might be a different / more applicable guide around; if anyone knows, do pitch in!

I do not have a good overview of lazy-loading img custom elements. There are a few around, but I haven’t tried them. Some implementations tend to overthink it imo, or mix the effect and the intent, so you might have to look around a bit.

On a similar note, I think the “coding” part of the lazy-loading is super fun with IntersectionObserver these days! If you want to try writing a custom element for this, I have some notes written down from a React image lazy-loading library that I maintain. I think the principles and state transitions can be a good reference.

4 Likes

I have been trying to use the Intersection Observer and have finally cracked it this morning. I was having issues when using the back button and not being able to find my lazy elements, I had to hack it a little bit and set a timeout when the “popstate” event was fired. I haven’t tested the timeout duration much, but 100ms is working. I’m sure this can be reduced.

you need to handle 3 scenarios

  1. Page load
  2. UrlChanged
  3. Back button pressed

The following code should give you good starting point for your requirements.

function onEntry(entry) {

  entry.forEach((change) => {

    if(change.isIntersecting) {

      change.target.classList.add('visible');
    }
    
  });
  
}

const intersect = () => {

  let options = {
    threshold: [1]
  };

  let observer = new IntersectionObserver(onEntry, options);

  let elements = document.getElementsByClassName('lazy');

  for (let elm of elements) {
    observer.observe(elm);
  }
}


(function() {

  window.addEventListener("load", intersect);

	if (window.history && window.history.pushState) {

		window.addEventListener('popstate', function() {

                 window.setTimeout(intersect, 100);

	        });
    
	}
  
})();

ports.urlChange.subscribe(url => {
  intersect();
})

These two web components seem useful:

And Google Developers has a very nice article about it: https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/

What is your use-case? Are you putting the images inside of a scrollable element?

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.