Dec 20

Image Display Elements

Learn about the different image elements and CSS solutions, configuring their attributes, and various considerations for selecting which method to use.

By Stephanie Eckles

Images on the web are hard. In this article, we're going to focus on the options for the display of responsive images.

There are a few different ways to add images to your page depending on what you care about in regards to what part of the image is displayed, the quality, and the performance. This is a high-touch overview that really only scratches the surface of these methods. Be sure to check the additional resources for more assistance researching the best method for your use case.

Basic img element

If you have optimized your image and aren't doing anything unusual with its display and aren't concerned about serving higher density images for retina screens, just a simple img will do.

<img src="image.png" width="600" height="400" />

I've intentionally added the width and height attributes here to give the browser information about the image's intrinsic aspect ratio. Evergreen browsers now will pick up on the computed aspect ratio and prop open the space necessary for the image while waiting for it to download which can reduce cumulative layout shift. Watch Jen Simmons explain more about how it works.

img with srcset

If you want to begin to have some performance gains, you can save out your image in multiple sizes. Then, define them within the srcset attribute on a single img along with the value of their intrinsic (actual) width or the pixel density you prefer to be used. The browser will select the optimum choice given conditions like the viewport size, resolution, user preferences, and bandwidth.

<img 
alt=""
src="image-small.jpg"
srcset="image-large.jpg 1600w,
image-medium.jpg 768w,
image-small.jpg 320w"

width="1600"
height="800"
/>


<img
alt=""
src="image-1x.jpg"
srcset="image-3x.jpg 3x,
image-2x.jpg 2x,
image-1x.jpg 1x"

width="1600"
height="800"
/>

We're still including width and height to give the browser the aspect ratio hint. It's ok that the browser might choose a different image size because the assumption is a single image is resized which means the aspect ratio is the same throughout, regardless of ultimate rendered size.

img with srcset and sizes

With only srcset to go off of, the browser still has to wait for CSS to help determine the size to render. You can provide an additional hint by also adding the sizes attribute which relates to approximately how large the image will render within your layout.

The sizes attribute will be ignored if srcset is not provided. This is because the matching size will inform which image within srcset to use. The other condition is that srcset must be using widths and not density for this relationship to work.

When using sizes, the format is [media condition] [display width], [media condition] [display width], [display width] where display width is the intended width in your layout. The last value in the list must not have the media condition.

The browser will use the first matching media condition in the list based on device size and then select the exact srcset size if there's a match or the next largest size if there's no exact match.

<img 
alt=""
src="image-small.jpg"
srcset="image-large.jpg 1600w,
image-medium.jpg 768w,
image-small.jpg 320w"

sizes="(min-width: 120ch) 33vw, 100vw"
width="1600"
height="800"
/>

In that example, I'm letting the browser know that on a larger viewport I expect my image to take up roughly a third of the available space because it will be in a 3-column grid. Below that point, I expect it to take up essentially full width so we don't have to be more specific than 100vw. This still leaves it up to the browser to choose exactly which image to serve to best fit the layout expectations I have provided as well as its other conditions mentioned previously.

Art directing with picture

If you would like more control over which image is used and the flexibility for varying aspect ratios (aka "art directing" the image selected), then look to the picture element.

This involves a series of source elements that use the media attribute to define the media condition at which an image should be displayed. It's essentially like defining media query breakpoints directly on the image with the advantage of the browser knowing exactly which image to choose and start downloading even when CSS isn't available yet.

<picture>
<source media="(min-width: 600px)" srcset="image-landscape.jpg">
<source srcset="image-portrait.jpg">
<img src="image-landscape.jpg" alt="">
</picture>

This method removes browser heuristics beyond viewport size from the equation and puts the responsibility back on you to provide the best image for the user. If your image maintains a consistent aspect ratio across various sizes, choose the img with srcset option or keep reading for a combination option.

Here's a video showing the art direction idea in action. Above 480px viewports, a landscape image is shown where a woman is laughing while sitting in a meeting at a Mac laptop with another woman who is partially visible turned to her with a hand raised mid-storytelling. Below that viewport size, the image is cropped in to feature the laughing woman.

Offering modern image formats

If your primary goal is to score some performance wins, then the picture element is again what you need. It allows you to list images using modern image formats like WebP, AVIF, and JPEG XL for the browser to select from, where the first supported type by DOM order of your source elements will be used.

<picture>
<source srcset="image.jxl" type="image/jxl">
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<source srcset="image.jpg" type="image/jpeg">
<img src="image.jpg" alt="" width="600" height="400">
</picture>

We're once again providing width and height attributes for this method to ask the browser to hold open space for the image to load into.

Prioritizing performance

To get the best of modern image formats while also allowing the browser to determine which image is best for the user's current context, we can use the srcset attribute on sources within picture. Users of browsers with support for WebP or other modern formats will enjoy a significant performance boost compared to only providing standard jpeg images within a single img srcset.

<picture>
<source
type="image/webp"
srcset="wreath-w_200.webp 200w,
wreath-w_660.webp 660w,
wreath-w_960.webp 960w"
>

<source
type="image/jpeg"
srcset="wreath-w_200.jpg 200w,
wreath-w_660.jpg 660w,
wreath-w_960.jpg 960w"
>

<img
src="wreath-w_660.jpg"
alt="A holiday wreath made of evergreens and pinecones hangs from a round metal doorknocker attached to a teal door."
width="960"
height="640">

</picture>

In the demo, resize your viewport and then hover over the <img> tag in dev tools to see which image type and size was selected by the browser. Since we haven't used the media attribute, if your browser has downloaded a larger size it may not switch to the smaller size for a resize event since there is no performance gain. A refresh may trigger a change in the size selected for smaller viewports.

Also, note that the chosen size depends on not just viewport CSS pixels but also pixel density which may cause a larger than expected image to be selected. As in, the 660w image doesn't mean that image will be selected at 660px viewports.

Demo of srcset on source in picture
/* ensure the image resizes with its container
as well as keeping its aspect ratio */

img {
max-width: 100%;
height: auto;
}

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Suscipit, reprehenderit doloremque. Tempore, esse dolorum? Quasi sunt sed temporibus perferendis, officia voluptatum sit fuga doloremque repellat, deleniti quod officiis esse mollitia.

A holiday wreath made of evergreens and pinecones hangs from a round metal doorknocker attached to a teal door.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Et exercitationem sint quis ullam quae, vitae libero doloremque dolores reprehenderit, fugit totam quisquam. Eum nostrum incidunt quas expedita nobis suscipit et!

You can take this method one step further since the source elements also support the sizes attribute. Note that you can only select a combo of either media and srcset, or srcset and sizes.

Boosting CSS background images with image-set

There are certainly reasons why adding an inline image may not be feasible due to using a CMS or other systems without full control over the HTML. In the cases where you at least have CSS control, you can still start to get some benefits similar to srcset by using the CSS function image-set.

Rather than supply widths, the available option is to mark a resolution such as 1x and 2x. The browser will choose the best match including assessing the resolution as a proxy to assume a lower resolution will be more efficient for low bandwidth.

There is also a type value for defining modern image formats but it doesn't have sufficient support yet. However, browsers that support image-set() also support webp format so we can use webp in image-set() as well as a fallback of a regular background-image with a jpg.

For the current best support, we need to include the -webkit prefixed version as well:

.image-set {
background-repeat: no-repeat;
background-size: cover;
background-image: url(wreath-w_660.jpg);
background-image: -webkit-image-set(
url(wreath-w_660.webp) 1x,
url(wreath-w_960.webp) 2x
);
background-image: image-set(
url(wreath-w_660.webp) 1x,
url(wreath-w_960.webp) 2x
);
}

This will behave differently than srcset since we can only give a hint at the resolution. But being able to draw out the more modern image format (even if a bit hacky right now) can still be worthwhile savings.

Styling picture as a background image

Thanks to modern CSS, we can mix up the best of all the techniques to enable using picture with modern formats and srcset and sizes as a background. The other benefit we'll get is being able to retain alt descriptions which are lost as a side effect of actual CSS background-image.

Here's the HTML setup for this effect:

<div class="background-picture">   
<div class="background-picture__content">
<p>Yay background picture!</h3>
</div>
<picture>
<source type="image/webp" srcset="wreath-w_200.webp 200w, wreath-w_660.webp 660w, wreath-w_960.webp 960w">
<source type="image/jpeg" srcset="wreath-w_200.jpg 200w, wreath-w_660.jpg 660w, wreath-w_960.jpg 960w">
<img src="wreath-w_660.jpg" alt="A holiday wreath made of evergreens and pinecones hangs from a round metal doorknocker attached to a teal door." width="960" height="640">
</picture>
</div>

To accomplish placing the text over the picture, we'll use CSS grid and a trick we first learned for the Day 6 holiday card generator for stacking elements.

Additionally, we've added one of my favorite CSS properties, object-fit, which makes the img behave as the container for its own contents. In other words, we gain the behavior of background-size but on a regular inline image.

You can even sprinkle in some art direction by using the companion property object-position which you can experiment with using my web app Object-Fit Focal Point.

Using CSS grid to stack content over the picture element
.background-picture {
display: grid;
/* create a single named grid area */
grid-template-areas: "bp";
}

.background-picture > * {
/* assign all direct children to the single grid area */
grid-area: bp;
}

.background-picture__content {
align-self: center;
/* bring above picture when picture is last in DOM order */
z-index: 1;
color: #fff;
text-align: center;
font-size: clamp(1.35rem, 5vw, 1.75rem);
font-weight: bold;
padding: 5vh 1rem;
}

.background-picture :is(img, picture) {
display: block;
}

.background-picture img {
object-fit: cover;
width: 100%;
height: 100%;
/* decrease brightness to improve text contrast */
filter: brightness(0.65) saturate(1.25);
}

Yay background picture!

A holiday wreath made of evergreens and pinecones hangs from a round metal doorknocker attached to a teal door.

The demo also includes a succinct bonus modern CSS technique to improve text contrast over the image by reducing its brightness with a filter. We also bumped up the saturation to prevent completely losing the image's vibrancy. You could take this a step further and manage the brightness and saturate values with custom properties.

Aligning the content over the background picture

To change from a centered alignment, you can place the content using the -self alignment properties available for CSS grid.

Additional resources on image display and performance

Understanding the elements we've reviewed, when to use them, and how to construct the attribute values is a complicated venture. Here are some additional recommended resources to help guide you to a scenario that works best for you.

First, I highly encourage you to review the MDN docs on each element:

Additionally, MDN has an excellent guide to responsive images that provides more demos of the things we touched on in this article.

Two tools to help prepare images:

Still confused on when to use which type? Read these resources to help you understand... well, the bigger picture 😉