Skip to main content
Back to all posts

Enhancing User Experience with Progressive Image Loading for Avatars

I just got back from Nigeria and nothing is more painful than trying to share your site at an event and waiting for it to load.

That experience was a wake-up call. Not everyone has blazing-fast internet, and my site needs to work everywhere. So when I got back, I immediately implemented progressive image loading for all the avatar images on my site. Let me show you what I did and why it matters.

Progressive image loading demonstration showing the blur-up effect transitioning to a sharp avatar image

What Even Is Progressive Image Loading?

You know that awkward moment when someone’s looking at your site and there’s just… blank spaces where images should be? Yeah, that. Progressive image loading fixes this by showing a blurry placeholder instantly, then smoothly transitioning to the real image when it loads. No more embarrassing white rectangles while your avatars slowly appear.

Why I Had to Fix This

After my Nigeria trip, I realized my site was built with a Silicon Valley bias - assuming everyone has fiber internet. But one avatar was killing the experience on slower connections. This fix makes the site feel instant, even on sketchy conference WiFi or mobile data.

How I Built It

The Cool Parts

  1. Blur-Up Technique: A base64-encoded low-resolution placeholder is used initially, which appears instantly with a blur effect.
  2. Smooth Transition: Once the full-resolution image is loaded, a CSS transition is applied to smoothly fade from the blurred placeholder to the sharp image.
  3. Preloading and Fallbacks: A preload hint is added for a PNG fallback image, complementing the WebP format to ensure broad compatibility.

The Actual Code

I only had to touch two files: Layout.astro and index.astro. Here’s what changed:

1. Wrapper Div with Placeholder

A wrapper <div> is added around the avatar image, styled with a blurred base64 placeholder:

<div class="avatar-wrapper" style="background-image: url('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAAAAAAAD/4Q...');">
  <img src="avatar.webp" alt="User Avatar" class="avatar-image" />
</div>

2. CSS Transitions

CSS transitions are employed to facilitate a smooth fade effect between the placeholder and the full-resolution image:

.avatar-wrapper {
  position: relative;
  overflow: hidden;
}

.avatar-image {
  width: 100%;
  height: auto;
  opacity: 0;
  transition: opacity 0.5s ease-in-out;
}

.avatar-image.loaded {
  opacity: 1;
}

3. JavaScript for Image Load Detection

JavaScript is utilized to detect when the full-resolution image has loaded, enabling the transition effect:

document.addEventListener('DOMContentLoaded', () => {
  const avatarImage = document.querySelector('.avatar-image');
  avatarImage.onload = () => {
    avatarImage.classList.add('loaded');
  };
});

4. Preload Hint

A preload hint is added to optimize the loading of fallback images:

<link rel="preload" as="image" href="avatar.png" type="image/png" />

Making Sure It Actually Works

I tested this thing everywhere I could think of:

  • First visit: The blur placeholder shows up immediately (no more blank spaces!)
  • The fade-in: Smooth as butter when the real image loads
  • Return visits: Images from cache appear instantly
  • When things break: Falls back gracefully if images fail to load
  • Throttled connection: Used Chrome DevTools to simulate my Nigeria conference WiFi - still works great

The Real-World Impact

Here’s what this actually means for real people using my site:

  • It feels faster: Even if the actual load time is the same, seeing something immediately makes a huge psychological difference
  • No more layout jumps: The page doesn’t jerk around as images pop in
  • Works everywhere: Whether you’re on fiber in San Francisco or mobile data in Lagos, the site feels responsive

Look, not everyone has great internet. My trip to Nigeria reminded me that I need to build for the real world, not just for my local development environment. This progressive loading fix is small, but it’s the kind of thing that makes the difference between someone staying on your site or bouncing because it feels broken.

Now I can confidently pull up my site at any conference, anywhere in the world, without that sinking feeling of “please load, please load, please load…”