Load Images Like a Champ with Progressive Loading

Blue calculator on green grid background showing low quality image at left and high quality at right

I recently looked for a simple solution to progressively load images over on my Handheld Computer Museum site but didn’t find anything that met that single criteria (given my JPGs weren’t setup as progressive themselves). 🙂 I whipped out techniques I thought might work like ye olde “lowsrc” <img> tag attribute to find out that’s been deprecated. Likewise, I tried to place a CSS background behind an <img> tag but images don’t start out as transparent before they’re loaded. Same goes for a <div> with a background image with an <img> element inside it.

As I mentioned, setting JPGs up as progressive in your graphics software of choice is best. In my case, the way I setup processing of my images doesn’t include that feature. Hence this solution/post.

Here’s the code (with caveats and explanation after):

HTML

<div class="pic" style="background-image: url(your-image-thumbnail.jpg);">
    <img src="your-image.jpg" class="loading" onload="javascript:this.classList.remove(\'loading\')" />
</div>

CSS

.pic {
    background-size: cover;
    display: block;
    width: 100%;
}
.pic img {
    display: block;
    height: auto;
    opacity: 1;
    transition: opacity .35s ease-out;
    width: 100%;
}
.pic img.loading {
    opacity: 0;
}

Examples

First, setup your <div> with the “pic” class and the path to your thumbnail or low-quality image via some inline CSS. From there, drop the <img> tag into your <div> with the higher quality image source, a “loading” class, and a bit of Javascript that, once the larger image loads, will remove the “loading” class.

The CSS is hopefully pretty straightforward as well. First, we position our <div> with the “pic” class and setup the background image to fully cover the area of that <div>. The <img> inside is styled as a block to take up whatever space it needs, a default opacity of 1 (basically opaque/not see-through), and a nice opacity transition that gently fades the full-quality image in once that “loading” class with full opacity is removed.

You could certainly put the Javascript in a central file and apply it only to images with that “loading” class but I went quick and easy in this case. Enjoy and hit me up on my Mastodon post with any questions or “well, actually…” thoughts. Cheers!