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)@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òng image-set() là xong fallback cho trình duyệt cổ.

Technical facts

Thuộc tínhChi tiết
SpecCSS Images Module Level 4
BaselineWidely Available từ 09/2023
Resolution descriptors1x, 2x, 3x, Ndpi, Ndppx, Ndpcm
Type descriptortype("image/avif"), type("image/webp"), ...
Chấp nhậnurl(), string, gradient, image(), cross-fade(), element()
Không cho phépNested image-set(), hai entry cùng resolution

Browser support

BrowserPhiên bản hỗ trợ đầy đủ
Chrome / Edge113+
Firefox105+
Safari17+ (cú pháp đầy đủ kèm type())
Opera99+

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, ::after vớ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òng background-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ểu type(). 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() trong image-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.