@unpic/astro
ascorbic/unpic-imgA high-performance, responsive image service and component library for
Astro. Generates a responsive <img>
tag that follows
best practices, with the correct srcset, sizes and styles. Detects image URLs
from most image CDNs and CMSs and can resize images with no build step. Detects
if you are hosting on a platform with a built-in image CDN and will use that for
local images, and falls-back to the default Astro image service.
Installation and usage
npm install @unpic/astro
@unpic/astro
has two parts, which can be used independently but work best
together:
- A component library which provides a
<Image>
component and a<Source>
component for art direction. - An Astro image service, which allows you to use the regular Astro Image component unchanged, and have it automatically generate the correct srcset and attributes for all images.
If you want to use Unpic with a UI framework on Astro, you should also install the Unpic package for that framework. There are packages for Lit, Preact, React, SolidJS, Svelte and Vue.
Astro image service
Unpic includes an Astro image service that can be used with the regular Astro
<Image>
component. If you enable the image service, then any <Image>
will be
automatically optimized and responsive, as well as anything else that uses
getImage
. It will automatically detect the CDN or CMS you are using and
generate the correct srcset
and attributes for you, and for local images will
use the built-in image CDN on Netlify and Vercel. All other images will be
optimized using Astro’s default sharp image service.
To enable the image service, add the following to your astro.config.mjs
file:
import { defineConfig } from "astro/config";
import { imageService } from "@unpic/astro/service";
export default defineConfig({
image: {
service: imageService(),
},
});
You can also pass options to the image service. The following options are available:
fallbackService
: The image service to use for local images and when the CDN can’t be determined from the image src. Value can be any supported image CDN, or “sharp” or “squoosh” to use the local image service. By default it will either use the local “sharp” service, or will try to detect available services based on the environment. This detection currently works on Netlify and Vercel.placeholder
: The default placeholder to display when images are loading. If this is set, the image will have a background set while the image is loading. For more details see the placeholder section.layout
: The default layout to use for images. This can be"constrained"
,"fullWidth"
or"fixed"
. For more details see this page.
These defaults will be used for @unpic/astro
components and Astro Image
components, but not for components from other UI frameworks.
This is how you would set the options:
import { defineConfig } from "astro/config";
import { imageService } from "@unpic/astro/service";
export default defineConfig({
image: {
service: imageService({
// This can usually be auto-detected
fallbackService: "netlify",
placeholder: "blurhash",
// This is the default
layout: "constrained",
}),
},
});
You can then use the regular Astro <Image>
component, and it will behave like
an @unpic/astro
component.
---
import { Image } from "astro:assets";
// It works with local images too
import lighthouse from "../lighthouse.jpg";
---
<Image src={lighthouse} width={800} height={600} alt="A lighthouse" />
<Image
src="https://cdn.shopify.com/static/sample-images/bath.jpeg"
width={800}
height={600}
alt="A lovely bath"
/>
Image
component
In almost all cases you can just use the Unpic Image
component, which will
generate an optimized, responsive image for you with automatic format detection.
It has more options than the Astro Image
component, so if you have the choice
it is recommended to use this component.
---
import { Image } from "@unpic/astro";
---
<Image
src="https://cdn.shopify.com/static/sample-images/bath.jpeg"
layout="constrained"
width={800}
height={600}
alt="A lovely bath"
/>
Source
component
If you need to do art direction, or handle different formats in a CDN that
doesn’t do auto-detection then you will need a <picture>
element. You can use
the Source
component to generate the correct <source>
elements for you. The
usage depends on what you are trying to do.
Art direction
Art direction is where you want to use different images at different screen
sizes. For example, you might want to use a portrait image on mobile and a
landscape image on desktop. You can do this with a <picture>
tag and the
Source
component.
First use a normal <picture>
tag, and then add a Source
component for each
image you want to use. The Source
component will generate a <source>
tag
with the correct srcset
and sizes
attributes for you.
Each Source
component takes a media
prop, which is a media query that will
be used to determine if the image should be used. The first Source
component
with a matching media query will be used, and the rest will be ignored. It also
takes src
, width
, height
and layout
props, which are the same as the
Image
component. This means you can either use the same image with a different
crop or layout, or a completely different image.
You need to include an <Image>
as the final element in the <picture>
tag.
This is used as a fallback for browsers that don’t support <picture>
, or if
none of the media queries match. In a <picture>
tag, any styling must be
applied to the <img>
tag, and are applied whichever <source>
is used.
<source>
tags themselves cannot be styled. When using art direction you must
set the unstyled
prop on the <Image>
element, because otherwise the image
will have the same styling at all screen widths. Instead you need to use CSS
media queries to style the <img>
tag.
---
import { Source } from "@unpic/astro";
---
<picture class="hero">
<!-- Large screens get a full-width hero image -->
<Source
src="https://images.unsplash.com/photo-1694406805270-f3a93e91f4b6"
media="(min-width: 601px)"
layout="fullWidth"
/>
<!-- Small screens get a constrained square image -->
<Source
src="https://images.unsplash.com/photo-1693711942336-f4f9963bd364"
media="(max-width: 600px)"
width={600}
height={600}
/>
<!-- Always include an Image as the final element -->
<Image
src="https://images.unsplash.com/photo-1693711942336-f4f9963bd364"
width={600}
height={600}
alt="Aurora"
unstyled
/>
</picture>
<style>
/* Style for all layouts */
.hero img {
object-fit: cover;
width: 100%;
}
@media (min-width: 601px) {
/* Style for full-width layout */
.hero img {
height: 600px;
}
}
@media (max-width: 600px) {
/* Style for constrained layout */
.hero img {
max-width: 600px;
/* Set the image aspect-ratio */
aspect-ratio: 1/1;
}
}
</style>
Placeholders
Unpic can generate a placeholder that is used as a background while the image is loading. This looks better than a white boxe, and can improve the site’s LCP score. You can either set a static color or CSS value, or for remote images you use one of the placeholder generation options. These are generated at build time by downloading and analysing a small version of the image. There are several supported values:
dominantColor
: The image will analysed and to find the dominant color, and a placeholder will be generated with that color. This is the smallest output.blurhash
: The image will be analysed and a placeholder will be generated using the blurhash algorithm. This will not use client-side JavaScript, but will instead generate a tiny image that will be used as a data URI. This is the next-smallest output.lqip
: A low quality image preview with be used as a placeholder. A tiny version of the image will be loaded and inserted as a data URI. This is the largest output.
To compare the options, see the demo.
To use a placeholder, set the placeholder
prop on the <Image>
or <Source>
,
or set the placeholder
option on the image service.
Please note that placeholders are currently only supported for Astro components and not for components from other UI frameworks. They also cannot be used for local images - in this case they will be ignored and no background will be shown.
Image Props
The component accepts all the props of an <img>
tag, plus the following:
layout
The resizing behaviour of the image.
constrained
: (default) the image will be rendered at a maximum ofwidth
andheight
, but will scale down automatically if the container is smaller, maintaining the aspect ratio.fullWidth
: the image will be rendered at full width of its container. This is optimized for full-width hero images. You can setheight
to a fixed value, which will mean the image will be rendered at that fixed height and scale horizontally to fill the container.fixed
: the image will be rendered at the exact size specified bywidth
andheight
priority
By default, images are loaded lazily. If priority
is set to true
, the image
will be loaded eagerly, and will be given high priority by the browser. This is
useful for images that are above the fold, particularly large ones such as hero
images.
background
Either an image URL, CSS gradient or CSS colour value. If set to auto
, a
low-resolution version of the image will be rendered as a background image, with
a blurred placeholder effect. This is still loaded from the remote server, so if
you can instead provide an inline base64-encoded version of the image or
background colour, you should do that instead. Look at
@unpic/placeholder
for a library that can generate these
placeholders.
Bear in mind that this is not removed after the image loads, so it will be visible if the image has transparency.
aspectRatio
Instead of specifying both width
and height
, you can specify can
aspectRatio
.
cdn
By default the CDN is auto-detected from the src
URL. If you want to override
this, you can specify a CDN object. See the
unpic for supported values.
breakpoints
By default the image breakpoints used in the srcset
are generated based on the
layout and image size. You can override this by specifying an array of
breakpoints. The breakpoints are specified as an array of numbers, representing
the width of the image in pixels.
Other props
Any prop supported by <img>
tags can be passed in, except srcset
which is
generated from src
. The following props are set automatically, but can be
overridden if you need to:
sizes
role
decoding
loading
fetchpriority
Source Props
The Source component must be wrapped in a <picture>
tag, and accepts the
following props:
media
A media query string. If this matches, the source will be used. Normally this
would be something like (min-width: 768px)
, but it can also be used for dark
mode detection, e.g. (prefers-color-scheme: dark)
or other media queries.
type
The MIME type of the image. This is used to generate the type
attribute of the
<source>
tag, but is also passed to the CDN to generate the correct image
type. Normally an image CDN will auto-detect the required image format, but not
all support it and in that case you can use this component with type
to
specify multiple image format options and the browser will choose the best
supported one.
Other props
It also accepts the following props that are used in the same way as in the Image component:
layout
src
width
height
aspectRatio
cdn
breakpoints