My website: Responsive images
Image generation is handled by a custom Astro integration, similar to @astrojs/image
, and all images are wrapped in a custom Figure
component for richer content and better semantics. The image optimisations are carefully synchronised with the layout. Aspect ratio awareness is mandatory to eliminate CLS.
Content and semantics
The Figure component:
- Adds
<figure>
and<figcaption>
semantics. - Provides content for the image caption.
- Provides an attribution for the caption (example below).
- Renders the
Image
component
The resulting HTML
<figure>
<span>
<image alt="{alt}" src="{...}" />
</span>
<figcaption class="cs-primary astro-DA36CKTJ">
{image title}
<span>
{image attributiom}
<a data-external href="{attrbution url}">Visit site</a>
</span>
</figcaption>
</figure>
Eliminating CLS
Images always take more time to load than the rest of the content. This causes CLS which impacts usability of the page negatively, as things shift around while it loads, and may deteriorate SEO ranking.
When rendering images, we acquire the width and height of the image via getImageFacts() and set the absolute (natural) dimensions directly on the HTML <img width="..." height="..." />
This allows the browser to reserve the space for the image, even if we are styling it with CSS, using something like width: 100%; height: auto
. Aspect ratio will be respected as long
Don't you just 😍 evolution? It only took 20 years. Before browser support for aspect-ratio we had to resort to padding-top + percentage technique. Big kudos to @Princesseuh
Example
Code:
![Photo of wall with stickers](./images/example.jpg 'Have a nice day, beautiful decay! // Photo by Ann H https://www.pexels.com/@ann-h-45017/')
Result
ℹ️ If you block the URL in the browser developer tools and refresh the page, the space required for the image is still preserved.
Image profiles
Note: Back in 2019, native responsive images were still a bit of challenge. But today, issues like @srcset and picture being a maintenance nightmare are a non-issue if you are using a framework like Astro and generating all picture
, source
and img
tags from within a component.
I need to specify which resolutions I want to generate and this depends on how the image is going to be displayed by the website's layout. This might be a bit tricky if you are using responsive layouts, and even trickier if you are using a fluid responsive scale for typography and a responsive space scale. But it is still doable.
The goal here is to serve higher resolution for hero images, and medium resolutions for images inlined in posts, and to have the browser select which resolution to load depending on the viewport's width. Also, for things like thumbnails, I probably want a single resolution, and even smaller.
All profiles are declared here: images/profiles.ts.
Default profile
The content column layout is never wider than ~700px so I are generating images only at two resolutions:
width: 700px
- loaded on all small screenswidth: 1400px
- loaded if the screen is wider than 1200 pixels
This should speed up download on all mobile devices.
ℹ️ If you resize the screen above/below 1200 and then click open image in new tab
, you will get the different resolutions.
Hero profile
For hero images, which take up 100% of the width of the site's <main>
, I extend the previous profile and add one extra resolution:
width: 700px
- loaded on all small screenswidth: 1400px
- loaded if the screen is wider than 650 pixelswidth: 2800px
- loaded if the screen is wider than 1200 pixels
Image formats
Out of the box @astrojs/image
was generating jpg
, avif
, and webp
versions (x2 resolutions). A simplistic look at can I use avif vs can I use webp indicates that I've got only Microsoft Edge to gain or loose.
-rw-r--r-- 461K dist/assets/file....1400-size.jpg
-rw-r--r-- 126K dist/assets/file....700-ize.jpg
-rw-r--r-- 433K dist/assets/file....1400-ize.webp
-rw-r--r-- 123K dist/assets/file....700-ize.webp
-rw-r--r-- 294K dist/assets/file....1400-ize.avif
-rw-r--r-- 93K dist/assets/file....700-ize.avif
Since avif
yields more compression (~30% smaller files) I'll drop the webp
format and use only avif
and jpeg
.
All browsers get small files, except Edge. Faster downloads ✨ better experience. Also, my builds are sped up because smaller / less files to output and upload. 🌲 Less energy consumption as well.