CSS image-set()
函数自 2012 年以来一直得到基于 Chromium 的浏览器的支持,并在 Safari 版本 6 以来得到支持。 支持最近在 Firefox 88 中实现。 让我们深入研究,看看我们今天可以使用 image-set()
做些什么,以及不能做些什么。
同一图像的多重分辨率
以下是对 image-set()
的 CSS 规范 的描述。
为用户的设备提供最合适的图像分辨率可能是一项艰巨的任务。 理想情况下,图像应与查看它们的设备分辨率相同,这在用户之间可能会有所不同。 但是,其他因素可能会影响决定使用哪个图像; 例如,如果用户处于缓慢的移动网络连接中,他们可能更喜欢接收低分辨率图像,而不是等待加载大型高分辨率图像。
它基本上是 CSS 背景,等同于用于 img
标签的 HTML srcset
属性。 通过使用 image-set
,我们可以提供图像的多重分辨率,并相信浏览器会做出最佳决策以决定使用哪一个。 这可用于为三种不同的 CSS 属性指定值:content
、cursor
,最有用的是 background-image
。
.hero {
background-image: image-set("platypus.png" 1x, "platypus-2x.png" 2x);
}
1x
用于标识低分辨率图像,而 2x
用于定义高分辨率图像。 x
是 dppx
的别名,代表 **每像素点单位**。
Chrome/Edge/Opera/Samsung Internet 目前需要 -webkit-
前缀。 如果您使用的是 Autoprefixer,这将自动处理。 Safari 不再需要前缀,但使用旧语法,该语法要求使用 url()
函数来指定图像路径。 我们也可以包含一个普通的 background-image: url()
来支持任何不支持 image-set
的浏览器。
.hero {
/* Fallback */
background-image: url("platypus.png");
/* Chrome/Edge/Opera/Samsung, Safari will fallback to this as well */
background-image: -webkit-image-set(url("platypus.png") 1x, url("platypus-2x.png") 2x);
/* Standard use */
background-image: image-set("platypus.png" 1x, "platypus-2x.png" 2x);
}
现在,使用昂贵的高端设备的用户将看到超级清晰的图像。 对于慢速连接或使用廉价屏幕的用户,性能将得到提升,因为他们的浏览器将自动请求低分辨率图像。 如果您想确保在高分辨率设备上甚至在慢速连接上也使用高分辨率图像,可以使用 min-resolution
媒体查询而不是 image-set
。 有关为高密度屏幕提供清晰图像的更多信息,请查看 Jake Archibald 最近发布的 博客文章。
这很酷,但我真正想要的是能够在 CSS 中采用最新的图像格式,同时仍然满足旧浏览器的需求……
新的图像格式
Safari 14 发布了对 WebP 的支持。 它是最后一个支持该图像格式的现代浏览器,这意味着该图像格式现在得到了所有浏览器的支持(Internet Explorer 除外)。 WebP 的优点是可以生成通常比 JPG、PNG 或 GIF 更小(但质量相同的)图像。
还出现了一堆更新的图像格式。 AVIF 图像 的尺寸惊人地小。 Chrome、Opera 和 Samsung Internet 已经发布了对 AVIF 的支持。 它已经在 Firefox 中处于旗帜状态。 这种图像格式尚未得到许多设计工具的支持,但您可以使用 Google Chrome 团队构建的 Squoosh 应用程序 将图像转换为 AVIF。 WebP 2、HEIF 和 JPEG XL 最终也可能会进入浏览器。 所有这些都非常令人兴奋,但我们希望不支持这些更新格式的浏览器也能获取一些图像。 幸运的是,image-set()
有一个为此提供的语法。
通过指定类型来使用新的图像格式
浏览器支持说明: 我将要讨论的 image-set
的功能目前在浏览器中支持得非常糟糕。 目前仅在 Firefox 89 中得到支持。
HTML 已经多年来支持 <picture>
元素。
<picture>
<source srcset="./kitten.avif" type="image/avif">
<img src="./kitten.jpg" alt="a small kitten">
</picture>
image-set
提供了 CSS 等效项,允许通过指定图像的 MIME 类型来使用下一代图像格式。
.div1 {
background-image: image-set(
"kitten.avif" type("image/avif"),
"kitten.jpg" type("image/jpeg")
);
}
下一代图像排在第一位,而旧浏览器的回退图像排在第二位。 仅下载一个图像。 如果浏览器不支持 AVIF,它将忽略它,并且仅下载您指定的第二个图像。 如果支持 AVIF,则会忽略回退图像。
在上面的示例中,我们使用了一个 AVIF 图像,并提供了一个 JPEG 作为回退,但回退可以是任何广泛支持的图像格式。 以下是如何使用 PNG 的示例。
.div2 {
background-image: image-set(
"puppy.webp" type("image/webp"),
"puppy.png" type("image/png")
);
}
在 Chromium 和 Safari 中,目前不支持指定 type
。 这意味着您今天只能使用 image-set
来指定广泛支持的图像格式的不同分辨率,而不能在这些浏览器中使用 WebP 或 AVIF 时添加向后兼容性。 如果您有这种倾向,应该可以同时提供多重分辨率和多重图像格式。
.div2 {
background-image: image-set(
"puppy.webp" type("image/webp") 1x,
"puppy2x.webp" type("image/webp") 2x,
"puppy.png" type("image/png") 1x,
"puppy2x.png" type("image/png") 2x
);
}
希望浏览器支持很快会得到改进。
<picture>
来显示背景
改用 也许您根本不需要 background-image
。 如果您想使用现代图像格式,您可以使用 <picture>
元素,它在浏览器中的支持度更高。 如果将图像设置为 position: absolute
,则可以轻松地在其上显示其他元素。
作为使用 position: absolute
的替代方法,CSS 网格是另一种轻松叠加 HTML 元素的方法。
以下是关于取消 image-set() 前缀的 Chrome 错误的链接。 请为它投票,让 Chrome 团队知道您想要它: https://bugs.chromium.org/p/chromium/issues/detail?id=630597&q=css%20image-set&can=2
感谢您提供链接。
这非常有帮助。 谢谢!
谢谢,但我还是想知道如何懒加载背景图像?
Lazysizes 有一个为此提供的 bgset 插件: https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/bgset
所有这些都很好,但我想知道有多少网站有资源和时间为所有内容图像创建图像集?
我想相当大的一部分只能负担得起一种图像格式,一种分辨率。
是的,可能是这样。 但是,嘿,现在我们不能再责怪 CSS 没有提供执行此操作的选项了。
好吧,如果您使用某些 CDN 来托管媒体文件,他们可能会有动态转换功能。 例如:`https://uploadcare.com/`。 您只需要上传最大的图像,然后就可以按需请求任何大小/质量的图像。
我个人更喜欢不再使用背景,因为出于可访问性的原因,您仍然无法在背景图像上放置任何与 SEO 相关的元数据。 对于大多数人使用背景图像的目的,现在可以使用 object-fit + object-position 来轻松实现。
现在唯一的实际用例是重复背景。
但仍然很高兴知道,终于找到了解决长期存在的性能问题的方案。
根据 Can I Use,
type()
函数得到所有主要浏览器的支持,/除了/ Safari(桌面和 iOS)。 请查看 https://caniuse.cn/css-image-set如果我使用 type() 函数,不支持该函数的浏览器(例如 Safari)是否仍然会执行规则的其余部分?或者我是否需要为 Safari 编写单独的规则,例如:
.div1 {
background-image: image-set(
"kitten.avif" type("image/avif") 1x,
"kitten.jpg" type("image/jpeg") 1x,
"kitten2x.avif" type("image/avif") 2x,
"kitten2x.jpg" type("image/jpeg") 2x,
"kitten.jpg" 1x, // 适用于 Safari
"kitten2x.jpg" 2x // 适用于 Safari
);
}
我尝试过这种解决方案,但它不起作用。无论如何,jpg 文件都会加载。
background-image: url("../../assets/images/banner2.jpg");
background-image: linear-gradient(to top, rgba(black, 0.6), rgba(black, 0.6)),
-webkit-image-set(url("../../assets/images/banner2.webp") 1x);
background-image: linear-gradient(to top, rgba(black, 0.6), rgba(black, 0.6)),
image-set(url("../../assets/images/banner2.webp") 1x);
这是我的代码。我甚至尝试过添加 type()。
谢谢 Ollie
它完美地工作
我们如何内联使用媒体查询? 1x 和 2x 不起作用。
我能想到的唯一方法是创建一个类,然后在专门的媒体查询中添加它们,但我找不到内联执行此操作的方法。
我使用的是一台新的 Macbook,安装了 Chrome 版本 102.0.5005.61,它应该没问题。但是我遇到了“无效属性值”的错误,并且它使用了备用选项。即使我粘贴了这里的示例,并使用了绝对图像 URL。你知道为什么会这样吗?
我在 MDN 文档中注意到它有时使用
background-image: image-set(
url(“large-balloons.avif”) type(“image/avif”),
有时使用
background-image: image-set(
“large-balloons.avif” type(“image/avif”),
我都尝试过,但没有效果。有什么想法吗?
嗨 Ben。这篇文章有点误导人,Ollie 说你 **不能** 在 Chrome 中使用
type()
,这是 **正确** 的,但随后他给出了一个使用type()
的示例,这 **不会** 工作。Chrome 中的
image-set
(在撰写本文时)必须添加前缀,
必须将 url 包裹在 url() 函数中
必须有 dppx 值,例如 1x、2x。
并且不能使用 type()
在我的测试中,任何其他组合都失败了。
这意味着,目前,image-set() 仅适用于设置要使用的图像的像素密度,除了 Firefox。
因此,要重写他的示例,它需要类似这样:
实际上,对于纯静态网站,我认为 WEBP 是我们目前唯一可以与 Chrome 和 image-set() 一起使用的有价值的格式。原因是 Edge 支持 -webkit-image-set(因为它是一个基于 Chromium 的浏览器),但尚不支持 AVIF。由于语法是正确的,但文件类型不受支持,Edge 会忽略背景图像,不会回退到第 6 行的 JPG。(我没有直接测试过,但通常情况下,当语法正确,但文件本身有问题时,例如损坏或 404,就会发生这种情况,但我乐于接受更正。)
此外,如果没有 type() 函数告诉浏览器其他 mime 类型可用,那么提供其他选项就没有意义。好消息是 WEBP 现在得到了很好的支持,但如果浏览器不支持 WEBP,那么它很可能也不支持 image-set,因此在这种情况下,它将回退到 JPG。
尽管如此,如果你可以使用 Ollie 建议的
<picture>
元素或图像 CDN,就可以绕过所有这些。希望对你有帮助