CSS image-set Table
| Piece | What it does | Field note |
|---|---|---|
image-set(url 1x, url 2x) | srcset for CSS | Responsive images inside CSS - backgrounds, masks, content |
Resolution descriptors | 1x / 2x / 600dpi | Browser picks by DPR - same negotiation as img srcset |
type: option | Format hints | image-set(avif 1x type("image/avif"), png 1x) - format AND size switch |
gradient in image-set | Any image value | Gradients and SVGs are valid options - fallback to solid |
vs img srcset | CSS vs HTML context | srcset for CONTENT images; image-set for CSS-declared images |
Fallback declared first | The cascade safety | background: url(fallback); background: image-set(...) - old engines keep first |
Performance win | No double download | Browser picks ONE file - unlike media-query stacking which fetches wrong guesses |
Baseline 2023 | Safe to ship | All evergreen browsers - the years of -webkit-image-set are over |
image-set() is srcset for CSS: image-set(url(hero-2x.png) 2x, url(hero.png) 1x) lets the BROWSER pick the right file by device pixel ratio - inside backgrounds, masks and content, the places HTML srcset cannot reach.
Bottom line: the type() option adds format switching (AVIF with PNG fallback) in the same declaration - format AND resolution negotiation together. The cascade pattern ships safety: declare the plain fallback background first, then the image-set line - old engines keep the first, evergreen browsers pick one file.
The honest part: baseline 2023 - the years of -webkit-image-set are over. The performance property that justifies it: the browser picks ONE file, unlike media-query stacking where wrong guesses prefetch images the layout never shows.
How to use
- Serve sharp backgrounds: background: image-set(url(bg-2x.jpg) 2x, url(bg.jpg) 1x) - every display gets its resolution, one declaration.
- Negotiate format too: image-set(avif-hero.avif 1x type('image/avif'), hero.png 1x) - AVIF where supported, PNG where not, same resolution logic.
- Ship the fallback first: background: url(bg.jpg); background: image-set(...); - the cascade keeps old engines on the plain URL, new engines on the set.
Frequently asked questions
What does image-set() solve that plain CSS background images could not?
Device-pixel-ratio awareness. A plain background: url(bg.png) ships one file to every screen: blurry on retina (1x file stretched over 4 physical pixels) or wasteful everywhere else (2x file downloaded for 1x screens). image-set() lists resolution options with descriptors (url 1x, url 2x) and the browser downloads exactly the file matching the device - the same negotiation img srcset performs, brought to every CSS image context: backgrounds, masks, border images, the content property. Before it was widely supported, the workaround was media queries stacking -webkit-device-pixel-ratio conditions - verbose, and it fetched wrong guesses.
How does the type() option extend the negotiation?
It adds FORMAT to the resolution axis. Each option can carry type('image/avif'), and the browser skips options whose format it cannot decode - so one declaration offers AVIF (smallest), WebP (middle), and PNG (universal): format negotiation and DPR negotiation in one function. The same idea exists in HTML as <source type> inside picture; image-set brings it to CSS contexts. The practical check is the same as srcset: the type strings must be valid MIME types, and the browser trusts them - a wrong type string excludes a file the browser could actually have used.
Why declare a plain fallback background BEFORE the image-set line?
Cascade safety for old engines. A browser that does not parse image-set() discards the entire declaration - if the image-set line is the only background, the element has NO background at all. Declaring background: url(bg.jpg) on the previous line means unsupported engines keep the plain file (cascade: later valid declaration wins, later INVALID declaration is ignored), while supporting engines override it with the image-set choice. It is the same fallback-first discipline as modern CSS features generally: the enhancement line comes second, the functional baseline comes first.
When is image-set the wrong tool compared to img srcset?
For CONTENT images. An image that is the content - a product photo, an article illustration - belongs in an <img> with srcset and sizes: it gets alt text, semantic loading semantics, lazy loading, and the browser's priority hints. image-set is for images that are DECORATION or style: backgrounds, masks, list bullets, pre-play posters on video. The dividing question: would this image appear in an RSS reader or matter to a screen reader? If yes, it is content - img. If it is presentation the page works without, CSS owns it, and image-set is how CSS images go responsive.