The Problem

Scenario: Fluidly sized images, before the images load, the image containers initially appear collapsed.

The problem here is the image containers don't initially have a height, and setting a fixed height would be wrong as we don't know how much space these fluid-width images are going to occupy once they load.

<div class="grumpy-image-wrapper">
    <img class="grumpy-image" src="images/grumpy-cat.jpg" />
</div>
    
.grumpy-image-wrapper {
    width: 90%;
    border: 2px solid white; /* simply to show you the collapsed state for this demo */
}
.grumpy-image {
    width: 100%;
}
    

Your image containers are going to look like this:

Before images have loaded:

After images have loaded:

This means the inital structure looks horrible and collasped, and whatever content you have directly below the images will suddenly shift down the viewport as the images load.

The Fix

Padding to the rescue! Here's what we need to know: the image ratio

If we know the ratio the image is going to be once the image has loaded, we can add this handy padding hack to the container, so it resizes fluidly to the correct dimensions:

Padding Bottom = (Image Height / Image Width) * 100%

Don't know the ratio? Perhaps you should explore a way of returning the image dimensions to the frontend before the images are requested. It's not the perfect solution but you will then be able to apply this padding dynamically via JavaScript.

In the case of my grumpy cat picture, the original image dimensions are 360 x 240, so my padding-bottom on the wrapper should be 66.67% to simulate the correct height.

(There's a couple more critical instructions below...)

<div class="grumpy-image-wrapper">
    <img class="grumpy-image" src="images/grumpy-cat.jpg" />
</div>
<div class="grumpy-image-wrapper">
    <img class="grumpy-image" src="images/grumpy-cat.jpg" />
</div>
<div class="grumpy-image-wrapper">
    <img class="grumpy-image" src="images/grumpy-cat.jpg" />
</div>
    
.grumpy-image-wrapper {
    width: 90%;
    height: 0;
    padding-bottom: 66.67%;
    border: 2px solid white;
    position: relative;
}
.grumpy-image {
    width: 100%;
    position: absolute;
}
    

More Important Instructions!

We also need to add position: absolute to the image, and position: relative to the wrapper, to ensure the padding is not added to the height of the image when the browser calculates the wrapper's height.

If you require extra padding on your image container, you will need to take this into account when calculating the amount of bottom padding to apply in this fix. If the amount of extra padding or border is not a %, then you'll probably need to look at using box-sizing: border-box, so your wrapper's dimensions aren't made any bigger by the box styling.

So, here's the result:

Before images have loaded:

After images have loaded:

Extras: how about a nice preloading state, and fading in images when they are ready?

If you're after some bells and whistles, here's a bit of extra code I like to implement, to give the image wrappers a nice preloading state, and fade in the images only when they have completely loaded:

Demo: https://jsfiddle.net/andyshora/5YVNN/

That's all for now!

Thanks for reading, as always please leave your questions and comments below!

Andy Shora: AI, Engineering and Innovation Leader