You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add optional AVIF output to the public Image component (emdash/ui), rendered as a <picture> element with an AVIF <source> and the current WebP img/srcset as fallback — similar to Astro's built-in <Picture> component and its formats option.
Motivation
The transform endpoints already support AVIF end to end: ALLOWED_TRANSFORM_FORMATS includes avif, the Cloudflare endpoint maps it to the IMAGES binding, and the Node path goes through sharp, which also encodes AVIF. But the Image component only ever emits a single-format WebP srcset, so that capability is unreachable for CMS media today.
AVIF is consistently 25–40% smaller than WebP at comparable visual quality. Measured on a production Worker (source JPEG, 122 KB original, 640×480 rendition):
Format
Size
WebP (q=85)
26 KB
AVIF
20 KB
On image-heavy pages (galleries, card grids) this adds up to a meaningful LCP/bandwidth win, and browser support is universal by now (Chrome, Firefox, Safari 16+). Sites currently can't opt into it without bypassing the component entirely.
Proposed API
A formats prop on the Image component, defaulting to the current behavior:
Default stays ["webp"] → plain <img> exactly as today, zero breaking change.
With multiple formats, render <picture> with one <source type="image/avif" srcset="…"> per extra format and the last format as the <img> fallback, reusing the existing buildResponsiveImage srcset logic per format.
<picture> is layout-neutral for the existing class/style contract if the attributes stay on the inner <img> (optionally display: contents on the picture).
Only applies to the local/storage-backed path where EmDash controls the transform URL; external providers keep their current getSrc behavior.
Alternatives considered
Content negotiation via Accept header in the transform endpoint — avoids markup changes, but breaks the immutable per-URL cache semantics (Cache-Control: immutable + Vary: Accept) and CDN cacheability; explicit URLs per format cache cleanly.
Making AVIF the default single format — smaller markup, but AVIF encoding is notably slower (relevant for the sharp path) and burns more unique transformations on the Cloudflare Images binding, so it should stay opt-in.
Happy to implement this (component change + tests + docs) if the direction sounds right. Related: #2037 fixed the missing quality default on the Cloudflare endpoint, which this would build on.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
Add optional AVIF output to the public
Imagecomponent (emdash/ui), rendered as a<picture>element with an AVIF<source>and the current WebPimg/srcsetas fallback — similar to Astro's built-in<Picture>component and itsformatsoption.Motivation
The transform endpoints already support AVIF end to end:
ALLOWED_TRANSFORM_FORMATSincludesavif, the Cloudflare endpoint maps it to theIMAGESbinding, and the Node path goes through sharp, which also encodes AVIF. But theImagecomponent only ever emits a single-format WebPsrcset, so that capability is unreachable for CMS media today.AVIF is consistently 25–40% smaller than WebP at comparable visual quality. Measured on a production Worker (source JPEG, 122 KB original, 640×480 rendition):
On image-heavy pages (galleries, card grids) this adds up to a meaningful LCP/bandwidth win, and browser support is universal by now (Chrome, Firefox, Safari 16+). Sites currently can't opt into it without bypassing the component entirely.
Proposed API
A
formatsprop on theImagecomponent, defaulting to the current behavior:["webp"]→ plain<img>exactly as today, zero breaking change.<picture>with one<source type="image/avif" srcset="…">per extra format and the last format as the<img>fallback, reusing the existingbuildResponsiveImagesrcset logic per format.<picture>is layout-neutral for the existingclass/style contract if the attributes stay on the inner<img>(optionallydisplay: contentson thepicture).getSrcbehavior.Alternatives considered
Acceptheader in the transform endpoint — avoids markup changes, but breaks the immutable per-URL cache semantics (Cache-Control: immutable+Vary: Accept) and CDN cacheability; explicit URLs per format cache cleanly.Happy to implement this (component change + tests + docs) if the direction sounds right. Related: #2037 fixed the missing quality default on the Cloudflare endpoint, which this would build on.
Beta Was this translation helpful? Give feedback.
All reactions