Closed ascorbic closed 3 weeks ago
In order to automatically generate the correct attributes for an image, we need to know how it should behave when resized. I propose introducing a layout
property to define this. When set, this will enable the new mode, and set defaults for all required attributes.
The most important attributes to set for best practices are shown below. These will all have appropriate values set, according to the specified layout. These can be overridden, but should not need to be in most cases.
srcset
: the most important extra attribute, and the one that is most likely for developers to know about, this tells the browser which image sources are available to download. There should be several entries, the sizes of which depend on the layout and image size.sizes
: a browser uses this attribute as a hint to help it choose which source to download. It is a set of media conditions, which normally contains viewport sizes for responsive images. This would be set automatically based on the layout and image size.loading
: by default, all images are loaded as soon as they are encountered in the HTML. This is not needed for images that are offscreen when the page loads, so should be set to lazy
for these. Currently set to lazy by default.decoding
: a browser needs to decode an image file before displaying it onscreen. This attribute is a hint as to whether this should happen while the page is rendering (sync
), or wait until the DOM is complete (async
). As with loading
, offscreen images should be decoded asynchronously for best performance. Currently set to async by default.fetchpriority
: this tells the browser what the priority should be for network requests for this image. The priority of the main images on your page can make a significant difference to your LCP, so should be high
for these. Similarly, setting offscreen images to low
means that the network is used for more important images that are visible onscreen when the page loads. <Image>
propertiesThere would be new properties added to the Image
component. The existing densities
property would not be supported when using the new image handling. widths
would be supported, but not recommended as it is better to allow it to be set automatically when using layout
.
layout
By default the images will have a class added that handles basic layout, as described below. These will be set at low specificity so they can be overriden by component and page styles. By default object-fit: cover
is set for all layouts unless overridden by the fit
prop. Layouts that preserve aspect ratio will have aspect-ratio
set as an inline style.
I propose the following layouts, but I am open to discussion:
height
is supplied then the height is fixed at that size when the width is resized, otherwise the aspect ratio is maintained. If width
is supplied, that will be the maximum width. Best for hero images that are displayed at the full width of the screen.priority
By default, images will be lazy loaded setting loading="lazy"
, decoding="async"
and fetchpriority="low"
. The boolean property priority
enables the opposite. This should be used for the LCP image, and other important images above the fold.
fit
Sets the object-fit
value. By default the value is cover
, which means image is resized to fill the container, while retaining the aspect ratio. This may mean that some edges are cut off if the aspect ratio is different. This can be changed to any other supported value, but the most useful is likely to be contain
, which resizes it to fit inside the specified size, while mainaining aspect ratio. This may leave space around the image if the aspect ratio does not match.
position
When cropping or padding an image where the aspect ratio does not match, the default behavior is to centre the image. Setting this will change the position. Some image services may support advanced values here that attempt to focus on a face or other point of interest. This will be documented by each service.
unstyled
If set, no style or class would be applied to the image. The developer would be responsible for setting the appropriate style for the image.
Would this be one way to ensure images are the correct size for the current screen/container size? https://developer.chrome.com/docs/lighthouse/performance/uses-responsive-images
For each image on the page, Lighthouse compares the size of the rendered image against the size of the actual image. The rendered size also accounts for device pixel ratio. If the rendered size is at least 4KiB smaller than the actual size, then the image fails the audit.
@lloydjatkinson yes. It would generate a srcset
with breakpoints at the right sizes.
Hi Ascorbic,
This is a nice write-up, and it looks very interesting.
As a beginner with Astro, and webdev in general, the pain point I've had with Astro's
width
and height
props. Would these still be necessary?the lack of "heavy" image modification (beyond the resizing and conversion) => One of the core team members said that it was not a desired feature back when they were creating the Astro components. I think it would be a great addition.
And some extra questions:
1) Would all these extra feature work on local images too?
2) The priority
prop: would that set a rel="preload"
link for that particular image, complete with [imagesizes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#imagesizes)
and [imagesrcset](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#imagesrcset)
attributes?
Thank you, and good luck!
Summary
The current Astro image component offers a lot of flexibility for displaying images. It supports
densities
andwidths
props to help generate the correctimg
attributes, and the default image service supports modern formats such as AVIF and WebP. While this gives users the tools to create performant and responsive images, it does not give guidance in how to use them - and requires that they are set on all images. This proposal is for a more opinionated image component. It would offer all of the tools from the current component, and also introduce new props and config options that follow best practices by default.Background & Motivation
Displaying images on the web is difficult, even for the most experienced developers. Users suffer slower page loads, and poor experience as the page layout jumps around. Meanwhile sites experience poor core web vitals scores for performance, cumulative layout shift (CLS) and largest contentful paint (LCP).
The most common
img
tag attributes are well known:src
,alt
,width
andheight
, there are several lesser-known attributes that are needed if an image is to have the best performance. All of these are optional according to the spec, but best practices require most of them. The most important aresrcset
,sizes
,loading
,decoding
andfetchpriority
.These are a lot of attributes to remember and understand, though the final three have values that are usually safe to think of as dependent on just whether the image is onscreen when the page loads. Astro Image already sets
loading
anddecoding
tolazy
andasync
by default. Howeversrcset
andsizes
have no simple rules because they depend on how the image will be displayed, and can be very hard to do correctly. Images also need to be styled correctly if they are to be responsive and avoid CLS.This proposal is inspired by the attributes generated by
@unpic/astro
, which I created, but with some changes to make it closer to the existing component behavior, and less focussed on image CDNs.Goals
layout
prop that, when combined with existing props, sets the attributes that will make an image responsive and following best practices.Non-goals
Example
Responsive images will be enabled by setting the
layout
prop toresponsive
,fixed
orfull-width
.A new
layout
option for theimage
config will default all images to that layout. This can be overridden on each image.References
These served as inspiration, and/or are useful for understanding best practices: