- image-set() cho phép browser tự chọn ảnh theo DPR (1x/2x/3x) và format (AVIF/WebP/JPEG) — zero JS, thuần CSS.
- Baseline Widely Available từ tháng 9/2023.
TL;DR
Khi phải gán background-image, image-set() nên là lựa chọn đầu tiên. Một dòng CSS duy nhất lo cả ba việc: chuyển đổi độ phân giải 1x / 2x / 3x, fallback giữa các format hiện đại AVIF → WebP → JPEG, và tất cả chạy thuần CSS — không cần JavaScript. Tính năng đã Baseline Widely Available từ tháng 9/2023, nghĩa là an toàn dùng trên mọi trình duyệt hiện đại hôm nay.
image-set() là gì?
image-set() là hàm CSS cho phép bạn liệt kê nhiều nguồn ảnh cho cùng một slot (thường là background-image), sau đó trình duyệt sẽ tự chọn nguồn phù hợp nhất dựa trên:
- Device Pixel Ratio (DPR) của màn hình — Retina 2x sẽ lấy ảnh 2x, màn hình thường lấy 1x.
- Format mà browser hỗ trợ — Chrome hiện đại chọn AVIF, Safari cũ hơn chọn WebP, trình duyệt rất cũ chọn JPEG.
- Băng thông — browser có thể xuống ảnh thấp hơn DPR trên kết nối chậm.
Nó chính là phiên bản CSS của thuộc tính srcset trên thẻ <img>, nhưng dùng được cho mọi CSS image property: background-image, mask-image, border-image, cursor, v.v.
Cú pháp
Hai dạng dùng nhiều nhất — chuyển resolution và chuyển format:
/* 1x / 2x / 3x switching */
.hero {
background-image: image-set(
url("hero.jpg") 1x,
url("hero@2x.jpg") 2x,
url("hero@3x.jpg") 3x
);
}
/* Modern format fallback */
.hero {
background-image: image-set(
url("hero.avif") type("image/avif"),
url("hero.webp") type("image/webp"),
url("hero.jpg") type("image/jpeg")
);
}Kết hợp cả hai — vừa đổi format vừa đổi độ phân giải trong một khai báo:
.hero {
background-image: image-set(
url("hero@2x.avif") type("image/avif") 2x,
url("hero@2x.webp") type("image/webp") 2x,
url("hero.avif") type("image/avif") 1x,
url("hero.webp") type("image/webp") 1x,
url("hero.jpg") type("image/jpeg")
);
}Trình duyệt quét từ trên xuống: loại bỏ các dòng có type() nó không decode được, rồi chọn dòng còn lại khớp DPR hiện tại.
Vì sao đáng dùng
Trước khi có image-set(), để làm cùng việc này với background-image bạn phải:
- Viết một loạt
@media (-webkit-min-device-pixel-ratio: 2)và@media (min-resolution: 2dppx)chồng lên nhau. - Dùng
@supportsđể phát hiện format và viết fallback thủ công. - Hoặc tệ hơn: nhét JavaScript detect DPR + format rồi swap URL động, phá cache và trì hoãn paint.
Với image-set(), tất cả logic đó đi vào một giá trị CSS. Ưu điểm cụ thể:
- Zero runtime cost — trình duyệt xử lý ở tầng parser, không block render.
- Cache-friendly — URL vẫn là URL tĩnh, CDN và service worker xử lý bình thường.
- Tương thích cascade — đặt một
background-image: url(fallback.jpg)ngay trên dòngimage-set()là xong fallback cho trình duyệt cổ.
Technical facts
| Thuộc tính | Chi tiết |
|---|---|
| Spec | CSS Images Module Level 4 |
| Baseline | Widely Available từ 09/2023 |
| Resolution descriptors | 1x, 2x, 3x, Ndpi, Ndppx, Ndpcm |
| Type descriptor | type("image/avif"), type("image/webp"), ... |
| Chấp nhận | url(), string, gradient, image(), cross-fade(), element() |
| Không cho phép | Nested image-set(), hai entry cùng resolution |
Browser support
| Browser | Phiên bản hỗ trợ đầy đủ |
|---|---|
| Chrome / Edge | 113+ |
| Firefox | 105+ |
| Safari | 17+ (cú pháp đầy đủ kèm type()) |
| Opera | 99+ |
Use cases thực tế
- Hero banner — giữ sharp trên MacBook Retina, nhẹ trên laptop 1080p.
- Dark-mode art direction — kết hợp với
prefers-color-schemeđể đổi cả ảnh theo theme. - Triển khai AVIF dần — ship AVIF cho ~95% user mà vẫn có JPEG safety net, không phải thay markup.
- CSS icon sprites — icon ở
::before,::aftervới bộ 1x/2x/3x gọn gàng. - Static site & email-safe components — nơi bạn không thể hoặc không muốn ship JS.
Limitations & gotchas
- Nếu browser không hiểu
image-set()toàn bộ, khai báo bị loại bỏ hoàn toàn. Luôn đặt một dòngbackground-image: url(fallback.jpg);ngay phía trên để cascade override đúng cách. - Safari dưới 17 hiểu
image-set()với resolution nhưng không hiểutype(). Baseline 09/2023 đã fix. - Browser có thể chủ động chọn nguồn thấp hơn DPR trên mạng chậm — đây là feature, không phải bug.
- Background image không có alt text — đừng đặt nội dung quan trọng vào đó; dùng thẻ
<img>cho ảnh mang nghĩa. - Không được nest
image-set()trongimage-set(). - Mỗi entry phải có resolution hoặc type duy nhất — không cho phép hai dòng cùng
1x.
Khi nào không nên dùng
Khi ảnh mang nội dung (logo, sơ đồ, ảnh bài viết) — hãy dùng thẻ <img srcset> hoặc <picture> để có alt, lazy loading có semantic, và accessibility đúng chuẩn. image-set() là dành cho ảnh trang trí trong CSS.
Còn nếu bạn đang viết một dòng background-image: url(...), năm 2026 nên thay ngay bằng image-set(). Một dòng, ba việc, zero JS.
Nguồn: MDN Web Docs, CSS-Tricks, web.dev Baseline 2023, @ipwanciu trên X.