我第一次制作响应式图片时,代码很简单,只有四行
img {
max-width: 100%;
height auto; /* default */
}
虽然这对开发人员来说足够了,但对用户来说并非最佳选择。如果 src
属性中的图片很重怎么办?在我的高性能开发设备(像我 16GB 内存的设备)上,几乎没有或不会出现性能问题。但是,在低端设备上呢?情况就不一样了。

上面的说明还不够详细。我来自尼日利亚,如果您的产品在非洲也能正常使用,那么您不应该只看上面的说明。请看这张图表

如今,最便宜的 iPhone 平均售价 300 美元。即使 iPhone 是衡量设备“速度”的标准,但大多数非洲人还是买不起。
这就是您需要了解的关于响应式图片的所有商业分析。您可能会问,什么才能做到呢?让我先解释一下图片是什么。
图片的细微之处
图片对用户很有吸引力,但对我们开发人员来说是一个艰巨的挑战,我们必须考虑以下因素
- 格式
- 磁盘大小
- 渲染尺寸(浏览器中的布局宽度和高度)
- 原始尺寸(原始宽度和高度)
- 长宽比
那么,我们如何选择正确的参数并巧妙地将它们混合匹配,从而为您的受众提供最佳体验呢?答案反过来取决于对这些问题的答案
- 图片是由用户动态创建的,还是由设计团队静态创建的?
- 如果图片的宽度和高度不成比例地改变,会影响质量吗?
- 所有图片是否都以相同的宽度和高度渲染?渲染时,它们必须具有特定的长宽比,还是完全不同的长宽比?
- 在不同的视窗上呈现图片时,需要考虑什么?
记下您的答案。它们不仅有助于您了解图片(来源、技术要求等),还有助于您在交付时做出正确的选择。
图片交付的临时策略
图片交付已经从简单地向 src
属性添加 URL 演变为复杂的场景。在深入研究它们之前,让我们谈谈呈现图片的多种选择,这样您就可以制定关于如何和何时交付和渲染图片的策略。
首先,确定图片的来源。这样可以减少不为人知的边缘情况的数量,并尽可能高效地处理图片。
一般来说,图片要么是
- 动态:动态图片是由受众上传的,这些图片是由系统中的其他事件生成的。
- 静态:摄影师、设计师或您(开发人员)为网站创建图片。
让我们深入研究每种类型图片的策略。
动态图片的策略
静态图片比较容易处理。另一方面,动态图片比较棘手,容易出现问题。如何才能减轻动态图片的动态特性,使它们更像静态图片一样可预测?有两件事:验证和智能裁剪。
验证
为受众制定一些关于什么可以接受、什么不可以接受的规则。如今,我们可以验证图片的所有属性,包括
- 格式
- 磁盘大小
- 尺寸
- 长宽比
注意:图片的渲染大小是在渲染过程中确定的,因此我们不需要验证。
验证后,会生成一组可预测的图片,这些图片更容易使用。
智能裁剪
处理动态图片的另一个策略是智能裁剪它们,以避免删除重要内容,并重新聚焦(或重新居中)主要内容。这很难做到。但是,您可以利用开源工具或专门从事图片管理的 SaaS 公司提供的 AI 功能。下面的部分将举一个例子。
为动态图片确定策略后,创建一个包含所有图片布局选项的规则表。下面是一个例子。甚至值得查看分析结果,以确定最重要的设备和视窗大小。
浏览器视窗 | HP 笔记本电脑 | PS4 Slim | 相机镜头/长宽比 |
---|---|---|---|
< 300 | 100 vw | 100 vw | 100 vw/1:2 |
300 – 699 | 100 vw | 100 vw | 100 vw/1:1 |
700 – 999 | 50 vw | 50 vw | 50 vw/1:1 |
> 999 | 33 vw | 33 vw | 100 vw/1:2 |
最基本(次优)的
现在,先把响应式的复杂性放在一边,只做我们最擅长的——简单的 HTML 标记,加上最大宽度 CSS。
以下代码渲染了一些图片
<main>
<figure>
<img src="https://res.cloudinary.com/...w700/ps4-slim.jpg" alt="PS4 Slim">
</figure>
<figure>
<img src="https://res.cloudinary.com/...w700/x-box-one-s.jpg" alt="X Box One S">
</figure>
<!-- More images -->
<figure>
<img src="https://res.cloudinary.com/...w700/tv.jpg" alt="Tv">
</figure>
</main>
注意:图片 URL 中的省略号 (...) 表示文件夹、尺寸和裁剪策略,这些细节太多,无法包含进来,因此被截断,以便专注于现在重要的内容。有关完整版本,请参阅下面的 CodePen 示例。
这是互联网上关于响应式图片的最简短的 CSS 示例
/* The parent container */
main {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
img {
max-width: 100%;
}
如果图片没有统一的宽度和高度,请用 object-fit
替换 max-width
,并将值设置为 cover
。

Jo Franchetti 在其关于 常见响应式布局与 CSS Grid 的博客文章中解释了 grid-template-columns
的值如何使整个布局自适应(响应式)。
查看 Pen
网格画廊,由 Chris Nwamba (@codebeast) 创建
在 CodePen 上。
然而,上面的代码并不是我们想要的,因为…
- 在高性能和低性能设备上,图片的大小和重量都相同,并且
- 我们可能希望对图片宽度更加严格,而不是将其设置为 250 并让它增长。
好了,本部分介绍的是“最基本的东西”,所以就到这里吧。
布局变化
图片布局最糟糕的事情就是对预期管理不善。由于图片可能具有不同的尺寸(宽度和高度),我们必须指定如何渲染图片。
我们应该智能地裁剪所有图片,使它们具有统一的尺寸吗?我们应该为一个视窗保留长宽比,而为另一个视窗改变长宽比吗?最终的选择权在我们手中。
对于网格中的图片,例如上面的示例中长宽比不同的图片,我们可以应用艺术指导技术来渲染图片。艺术指导可以帮助实现类似于下图的效果

有关响应式图片中分辨率切换和艺术指导的详细信息,请阅读 Jason Grigsby 的系列文章。另一个信息丰富的参考是 Eric Portis 的响应式图片指南,第 1、2 和 3 部分。
查看下面的代码示例。
<main>
<figure>
<picture>
<source media="(min-width: 900px)" srcset="https://res.cloudinary.com/.../c_fill,g_auto,h_1400,w_700/camera-lens.jpg">
<img src="https://res.cloudinary.com/.../c_fill,g_auto,h_700,w_700/camera-lens.jpg" alt="Camera lens">
</picture>
</figure>
<figure>
<picture>
<source media="(min-width: 700px)" srcset="https://res.cloudinary.com/.../c_fill,g_auto,h_1000,w_1000/ps4-pro.jpg">
</picture>
<img src="https://res.cloudinary.com/.../c_fill,g_auto,h_700,w_700/ps4-pro.jpg" alt="PS4 Pro">
</figure>
</main>
我们渲染了 700 像素宽的图片,而不是只渲染一个 700 像素宽的图片,如果视窗宽度超过 700 像素,则只渲染 700 像素 x 700 像素的图片。如果视窗更大,则会发生以下渲染
- 相机镜头图片被渲染为宽度 700 像素、高度 1000 像素的肖像图片(700 像素 x 1000 像素)。
- PS4 Pro 图片被渲染为 1000 像素 x 1000 像素的图片。
艺术指导
通过裁剪图像以使其响应式,我们可能会无意中删除主要内容,例如主体的面部。如前所述,AI 开源工具可以帮助智能裁剪并重新聚焦图像的主要对象。此外,Nadav Soferman关于智能裁剪的帖子 是一个有用的入门指南。
严格的网格和跨度
本文中关于响应式图像的第一个示例是一个灵活的示例。在最小的 300 像素宽度下,网格项目会根据视窗宽度自动流入适当位置。太棒了。
另一方面,我们可能希望根据设计规范对网格项目应用更严格的规则。在这种情况下,媒体查询非常有用。
或者,我们可以利用grid-span
功能来创建不同宽度和长度的网格项目
@media(min-width: 700px) {
main {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
}
@media(min-width: 900px) {
main {
display: grid;
grid-template-columns: repeat(3, 1fr)
}
figure:nth-child(3) {
grid-row: span 2;
}
figure:nth-child(4) {
grid-column: span 2;
grid-row: span 2;
}
}
对于在宽视窗上为 1000 像素 x 1000 像素正方形的图像,我们可以将其跨度设置为在行和列上占用两个网格单元。在较宽的视窗上变为纵向方向(700 像素 x 1000 像素)的图像可以在一行上占用两个单元格。
查看代码笔
网格画廊 [艺术指导] 由 Chris Nwamba (@codebeast)
在 CodePen 上。
渐进式优化
盲目优化就像没有优化一样糟糕。不要在没有预先定义适当测量的情况下专注于优化。如果优化没有数据支持,就不要进行优化。
尽管如此,在以上示例中仍然有很大的优化空间。我们从最基本的要求开始,向您展示了一些很酷的技巧,现在我们已经拥有了一个可用的响应式网格。下一个要问的问题是,“如果页面包含 20-100 张图像,用户体验会好吗?”
答案是:我们必须确保在渲染大量图像的情况下,图像的大小适合渲染它们的设备。为了实现这一点,我们需要指定多个图像的 URL,而不是一个 URL。浏览器将根据标准选择最合适(最优)的图像。这种技术称为响应式图像中的**分辨率切换**。查看此代码示例
<img srcset="https://res.cloudinary.com/.../h_300,w_300/v1548054527/ps4.jpg 300w,
https://res.cloudinary.com/.../h_700,w_700/v1548054527/ps4.jpg 700w,
https://res.cloudinary.com/.../h_1000,w_1000/v1548054527/ps4.jpg 1000w" sizes="(max-width: 700px) 100vw, (max-width: 900px) 50vw, 33vw" src="https://res.cloudinary.com/.../h_700,w_700/v1548054527/ps4.jpg 700w" alt="PS4 Slim">
Harry Roberts 的推文直观地解释了发生了什么
到目前为止,我发现解释
srcset
和sizes
的最简单方法是:pic.twitter.com/I6YW0AqKfM— Harry Roberts (@csswizardry) 2017 年 3 月 1 日
当我第一次尝试分辨率切换时,我感到困惑并发了推文
我知道 img srcset 属性中的宽度描述符表示图像源宽度(原始文件宽度)。
我不知道的是,为什么需要它?浏览器如何使用该值?cc @grigs 🤓
— Christian Nwamba (@codebeast) 2018 年 10 月 5 日
向 Jason Grigsby 在回复中做出的澄清表示敬意。
由于分辨率切换,如果浏览器大小发生调整,它就会为正确的视窗下载正确的图像;因此,对于小型手机(对 CPU 和 RAM 有好处)使用小型图像,对于较大视窗使用较大图像。

上表显示,浏览器以不同的磁盘大小(红色矩形)下载相同的图像(蓝色矩形)。
查看代码笔
网格画廊 [优化] 由 Chris Nwamba (@codebeast)
在 CodePen 上。
Cloudinary 的开源且免费的 响应式图像断点生成器 对于将网站图像适应多个屏幕尺寸非常有用。但是,在许多情况下,仅设置srcset
和sizes
就足够了。
结论
本文旨在为在许多(且可能令人困惑的)可用选项中设置响应式图像和布局提供简单但有效的指南。请熟悉 CSS 网格、艺术指导和分辨率切换,您很快就会成为忍者。继续练习!
您知道是否存在一种原生方法可以同时实现这一点和延迟加载图像吗?
我总是遇到像素密度问题。通常,设备越小,像素密度就越高。因此,如果您为较小的屏幕提供低分辨率图像,最终得到的图像看起来非常模糊 - 当我们尝试这样做时,客户总是抱怨他们在 iPad 和 iPhone 上看到的图像质量多么糟糕。我们最终提供的文件大小仅比原始文件小 5-10%,却需要投入大量的开发人员时间。
对于不是图片库的网站,并且每页不必加载 50 张图片,我们发现最好还是使用旧方法,并确保在上传时对图片进行适当优化。大多数图片的大小约为 80kb,即使是大型图片,最大也只有 150kb。