Image lazy load test page

Attribute Investigation

NB: The following numbers change as I add more text here because the images are getting pushed further down the page.

OK, so I don’t understand why this isn’t working in a normal page, then. Trying on an actual page:

Testing via Israel Blogpost:

OK, we have our work cut out for us:

Lazy Loading Background Blur Images

Nice guide with snippet for accomplishing this for background images, where it’s not natively done in browsers.

This totally worked! Wow, it’s so thrilling when things are possible. It looks like this:

let lazyBGs = [].slice.call(document.querySelectorAll(".svgBlur"));
if ("IntersectionObserver" in window) {
let lazyBGObserver = new IntersectionObserver((elements, _observer) => {
elements.forEach((el) => {
if (el.isIntersecting && el.target.hasAttribute("data-background-image")) {
// replace the background-image style with the contents of the data-background-image attribute
el.target.style.backgroundImage = el.target.getAttribute('data-background-image');
lazyBGObserver.unobserve(el.target);
}
});
});

lazyBGs.forEach((lazyBG) => {
lazyBGObserver.observe(lazyBG);
});
}

With that, we’ve kept the weight down to ~7MB.

Making Inline Markdown Images Lazy

Some pointers here. The super simple markdown-it-image-lazy-loading plugin worked a like a charm. We’re now down to 3MB (!!!), which is just the images Chrome fetches that are at the top of the page. Amazing. (Once I turn the interactive maps back on, this goes up to 5MB, which is totally acceptable.)

Big List of Images for Testing

I’m omitting the gazillion image tags and variants I used for testing here. Here’s a script to generate different versions for posterity:

#!/bin/bash

#
# Prepare a list of images from a file called imgs.txt that has local paths, one
# per line, like:
# assets/posts/2022-israel/IMG_1748.moz80.jpg
# ... and spits out a bunch of HTML tags (including leading slash) for testing
# many images per page and lazy loading, like:
# <img src="/assets/posts/2022-israel/IMG_1748.moz80.jpg" />
#

set -eu -o pipefail

while read f; do
# no lazy load:
# identify ${f} | pyp 'fn, _, dims, *rest = x.split(" "); x,y = dims.split("x"); print(f"<img src=\"/{fn}\" />")'

# works:
# identify ${f} | pyp 'fn, _, dims, *rest = x.split(" "); x,y = dims.split("x"); print(f"<img src=\"/{fn}\" width=\"{x}\" height=\"{y}\" loading=\"lazy\" />")'

# house style w/ lazy only ... works??
# identify ${f} | pyp 'fn, _, dims, *rest = x.split(" "); x,y = dims.split("x"); print(f"<div class=\"full-width flex justify-center ph1-m ph3-l fig\"><img class=\"db bare novmargin\" src=\"/{fn}\" style=\"max-height: min(100vh, 939px);\" loading=\"lazy\" /></div>")'

# combines house style w/ explicit width + height, but also CSS `width: auto; height: auto;` (no improvement)
identify ${f} | pyp 'fn, _, dims, *rest = x.split(" "); x,y = dims.split("x"); print(f"<div class=\"full-width flex justify-center ph1-m ph3-l fig\"><img class=\"db bare novmargin\" src=\"/{fn}\" style=\"max-height: min(100vh, 939px); width: auto; height: auto;\" width=\"{x}\" height=\"{y}\" loading=\"lazy\" /></div>")'
done < imgs.txt

Footnotes


  1. Without the interactive maps, it’s 117 requests, 72MB (vs ~73MB). So map tiles are lots of requests but small images. Not worth stressing about. ↩︎