How toOptimize image loading with plain HTML
If you're building some page like a landing with some images, you may want to optimize how these images load to ensure the page loads as fast as possible. Let's see how we could leverage different features of HTML to do that.
The plain image
Let's start with the simplest way to load an image.
<img src="/image.jpg" alt="a description of the image" />
This is our image, but it's not optimized at all. It may even cause a layout shift.
Add the size
The first thing we need to do is add the image size to the tag using the width
and height
attributes.
<img
src="/image.jpg"
alt="a description of the image"
width="1000"
height="400"
/>
Note that the size we define doesn't need to be the size the image will use when displayed on our landing. We can still change that with CSS, for example, by doing.
img {
height: auto;
max-width: 100%;
}
Now our image will try to use the size available of the container.
The reason to add the size as a fixed value in the HTML tag is to let the browser know the image's aspect ratio.
This way, if the browsers know that the image will be rendered inside a container of 500px.
They can also calculate that the height should be 200px and keep the size the image will need as the image load to avoid a layout shift.
Use a better format
Instead of using jpg
or png
we could use a more optimized format like webp
or avif
.
webp
is currently supported on all modern browsers, but avif
is only supported on Chrome and Firefox. So we could start using webp
directly.
<img
src="/image.webp"
alt="a description of the image"
width="1000"
height="400"
/>
Load a different version based on the pixel density
Some screens have a different pixel density, like a retina screen. If we want to load an image with a pixel density of 2, we could use the srcset
attribute.
Some devices may have other pixel densities too. We should also support 3x and 4x.
<img
src="/image@4x.webp"
alt="a description of the image"
width="1000"
height="400"
srcset="
/image.webp 1x,
/image@2x.webp 2x,
/image@3x.webp 3x,
/image@4x.webp 4x
"
/>
The srcset
attribute receives the different versions of the image, and the 1x
defines the pixel density we aim for with that version of the image. The src
should load the larger image to ensure it works on every device if the srcset
is not supported by the browser, which is not going to happen in all modern browsers anyway.
Load a different version based on the screen size
Another thing we could do is to change the image based on the screen size. This usually happens if the image on mobile has to change completely.
For example, we could show an image with more height and width on mobile and desktop, one with more width than height to accommodate the device screen.
We could also use srcset
to do that, but we can't have a different version per pixel density. To combine the image, we could use the picture
tag.
<picture>
<!-- this will be the desktop image -->
<source
srcset="
/desktop.webp 1x,
/desktop@2x.webp 2x,
/desktop@3x.webp 3x,
/desktop@4x.webp 4x
"
media="(min-width: 768px)"
width="1000"
height="500"
/>
<!-- This will be the mobile image -->
<source
srcset="
/mobile.webp 1x,
/mobile@2x.webp 2x,
/mobile@3x.webp 3x,
/mobile@4x.webp 4x
"
media="(max-width: 768px)"
width="5000"
height="1000"
/>
<!-- the fallback is picture is not supported -->
<img
src="/image@4x.webp"
alt="a description of the image"
width="1000"
height="400"
srcset="
/image.webp 1x,
/image@2x.webp 2x,
/image@3x.webp 3x,
/image@4x.webp 4x
"
/>
</picture>
This way, we have a source for desktop and another for mobile, each with its own srcset
loading a different image per pixel density.
And we still have the img
tag, which works as a fallback if picture
is not supported and lets us set the width, height, and alt text. We should do it there if we had to add a CSS class.
Preload the image
The next thing we could do is to preload the image. When the browser is still parsing the head
tag of the HTML document, it can start to load the image. Once it reaches the picture
tag, it may have already downloaded or started to load the image.
To do this, we can use the link
tag.
<link rel="preload" href="/desktop.webp" as="image" />
This is the primary way to use it, but we also have to load a different image per pixel density and screen size in our case. If we use the link above, we will always load the desktop image for 1x, even if it's not needed.
<link
rel="preload"
as="image"
href="/desktop@4x.webp"
imagesrcset="/desktop.webp 1x,
/desktop@2x.webp 2x,
/desktop@3x.webp 3x,
/desktop@4x.webp 4x"
media="(min-width: 768px)"
/>
<link
rel="preload"
as="image"
href="/mobile@4x.webp"
imagesrcset="/mobile.webp 1x,
/mobile@2x.webp 2x,
/mobile@3x.webp 3x,
/mobile@4x.webp 4x"
media="(max-width: 768px)"
/>