🚀 Adding Responsive Images to Astro Blog Posts #
Let’s take a look at the built-in Astro Picture component. Astro Content Collections offer a fantastic Developer Experience for building Markdown blog or documentation sites, but did you know how well they dovetail with the Picture component?
The Astro Picture component does the heavy lifting in adding responsive image markup to your
content sites. If you have ever had to construct HTML <picture>
tags from scratch, you will know supporting devices with different capabilities and screen-sizes
in a performant way is not easy.
Usually with responsive images, we mean serving large, double pixel density images, for users with Retina displays, but dialling down the resolution for a user on a smaller mobile device, which is able to make the image look equally sharp with a fraction of the pixels.
Responsive and Next‑gen Images #
Sending the right sized image for the user device, reduces the number of bytes streamed. Another popular way of reducing shipped image bytes is using WebP and AVIF images. These next-gen formats should encode images more efficiently, allowing for smaller files, though older devices do not support them.
😕 The Astro Picture Component #
The HTML <picture>
tag, essentially, is a way of communicating
to the browser which formats you have available on the server and in what sizes, and letting the browser
pick the most suitable one. You can imagine, adding this much detail for each image can become cumbersome.
And we haven’t even mentioned adding markup to prevent Cumulative Layout Shift (CLS) yet!
The Astro Picture component is designed to help you here, saving you from having to construct that
HTML <picture>
tag yourself. In this post, we see how you
can work with the Astro Picture component to add a banner image to each post on a blog site. As a bonus,
we also look at using Astro Content Collections, to generate a low-resolution placeholder image to
display while the banner image is loading.
🧱 What are we Building? #
Instead of building a new blog from start-to-finish, we’ll just see the steps you need to add banner images to blog posts to an existing Astro Markdown site with Content Collections . There is a link to the complete project code further down the page.
👮🏽 Content Collections #
Content collections are invaluable for making sure your content Markdown front matter has all the
fields you need it to have. The schema uses zod
under the hood , so you might already be familiar with the syntax. Here, we will see how you can also use the
schema to generate the image metadata needed for use with Astro’s Picture component.
The first step is to place the banner image in the content folder, within your Astro project. Here, I copied the image I want to use to the same directory as the Markdown file containing the post content.
Then, above, you can see I added a featuredImage
field to the post
front matter, with the path to the image (path is relative to the Markdown file’s own path, src/content/posts/best-medium-format-camera-for-starting-out/index.md
). Equally important is the image alt text (in line 6
), which we
also want to feed into the Astro Picture component.
Schema File #
The next change is to the schema file (at src/content/config.ts
).
A schema is not required for using Content Collections generally, though you will need one to
generate the image meta. See zod
docs for explanation of anything that
you are not familiar with, or drop a question below in the comments.
For Astro to generate the image metadata, just include the image function as an argument to the
callback in line 5
, and call that same function on the featuredImage
field. If you include multiple image fields in the front matter, you can call image
on each.
Calling image
automatically generates the following fields for the
picture, which we use in the next section:
🧩 Adding the Astro Picture Component #
The final missing piece of the puzzle is pulling in the metadata generated in the schema to an
instance of the Astro Picture component. The first step, then, is to extract that metadata within
the front matter section of the blog post page template (src/pages/[slug].astro
):
Adding the Picture Component to Astro Markup #
To finish off, let’s add the Astro Picture component to the markup:
-
We imported the Picture from
astro:assets
in line2
of the front matter. -
The component has the attributes you expect on a regular HTML
img
tag, such assrc
,alt
andloading
. -
For most images,
loading
will belazy
, to optimize page load. Generally, though, for a banner image or other large contentful object initially displayed, you will pickeager
, and also, to setfetchpriority
tohigh
.
Notice, we also have densities
, formats
and fallbackFormat
props. These are used to generate the final HTML
<picture>
tag.
-
densities
are the pixel densities used for high resolution screens, like Retina displays, typically1.5
and2
will be just fine here. -
formats
are the next-gen formats you want the images available in. To be safe, you might choose justwebp
as there have been issues with displaying someavif
images in Safari . An alternative is to use content negotiation . -
fallbackFormat
this is the format you want older browsers to use (browsers which do not support WebP or AVIF), and is probably the format of the original image.
Generated HTML Markup #
Using the above parameters, the final markup looks something like this:
Notice the image URLs include a hash in the path, which is ideal for cache-busting.
🏆 Level it up: Low Resolution Placeholder #
You might not have known it is possible to transform front matter fields within the Content Collection schema file. We can use this feature to generate low resolution placeholders automatically, using the ThumbHash algorithm .
To start, let’s add a placeholder field to the front matter:
To avoid using undocumented Astro APIs (which might later change), I have included the post folder name in the path here. This is different to how we added the featured image itself.
Next, we can add the transformation to our schema (src/content/config.ts
):
Here, I added a Rust WASM helper package (@rodneylab/picpack ) to generate the placeholder using ThumbHash. The arrow function in the placeholder
field (lines 15
– 19
) reads the bytes from the image and generates a Base64-encoded placeholder. We took the image
path and transformed the field to make a placeholder Base64-encoded string available in the Astro
page template.
Placeholder Markup #
We have an extra <img>
element, which will contain the placeholder.
Its src
is the Base64 placeholder, which we just generated in the schema
transformation. Notice in line 60
, the pictureAttributes
prop lets us add a class to the generated <picture>
tag.
The final missing piece is a spot of CSS to place the full-scale image on top of the placeholder, so that it displays (over the placeholder) as soon as it loads:
You can go to town on this, adding a touch of JavaScript to blend the placeholder into the full-scale image once it is loaded, though we won’t get into that here.
Astro Picture Component Alternatives #
Hopefully, this has given you an idea of how the Astro Picture component works, and whether it
will be suitable for your own project. You might also consider the unpic
project as an alternative . It is designed to work with hosting services (such as Imgix), and has an Astro-specific image
component.
You can also roll your own. The sharp image plugin is a good starting point. It is performant, and runs in environments other than Node.js: Deno and Bun, for example.
🗳 Poll #
🙌🏽 Astro Picture Component: Wrapping Up #
In this post, we saw how you can add responsive banner images to your Astro blog Markdown posts. In particular, we saw:
- how you can automatically generate image metadata using Content Collection schema;
- how you can transform front matter fields to generate Base64 placeholder images from image paths; and
- some options available on the Picture element to control the generation of next-gen AVIF and WebP alternatives for devices of different display sizes.
You can see the full code for this project in the Rodney Lab GitHub repo . I do hope you have found this post useful! Let me know how you add pictures to your site, whether you use the Astro Picture components, go for unpic with a hosting service or build something more manual. Also, let me know about any possible improvements to the content above.
🙏🏽 Astro Picture Component: Feedback #
Have you found the post useful? Would you prefer to see posts on another topic instead? Get in touch with ideas for new posts. Also, if you like my writing style, get in touch if I can write some posts for your company site on a consultancy basis. Read on to find ways to get in touch, further below. If you want to support posts similar to this one and can spare a few dollars, euros or pounds, please consider supporting me through Buy me a Coffee.
Just dropped a new post on using the new Astro Picture component.
— Rodney (@askRodney) November 6, 2023
You use:
— Astro Markdown APIs;
— Content Collection schema to generate a Base64 placeholder with ThumbHash; and
— the responsive Astro Picture component.
Hope you find it useful!
https://t.co/5O8SgVyYJj
Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on X, @rodney@toot.community on Mastodon and also the #rodney Element Matrix room. Also, see further ways to get in touch with Rodney Lab. I post regularly on Astro as well as SEO. Also, subscribe to the newsletter to keep up-to-date with our latest projects.