响应式图片初学者指南:如何让它们正确

776 阅读10分钟

如果你对响应式设计比较陌生,或者你只是想,能在你的项目中用 HTML 和 CSS 实现响应式图片的不同方式,有个快速参考,这篇响应式图片指南应该有所帮助。

现阶段,让网站在不同设备和平台看起来不错和表现良好,是一个好的网站设计和开发的重要组成部分。在”移动端设计“和”桌面端设计“已经没有什么分隔了,如今构建的每个网站在每个设备上应该是响应式并且运行得很好的。响应式设计过程的一个重要部分,就是响应式图片。

用简单的 CSS 实现响应式图片

一个最简单的方式,在一个网页中让任何一张图片变成响应式,不需要媒体查询或者额外的 HTML。你可以用几行 HTML 和 CSS 代码,让任何图片根据窗口大小变大或变小。

首先,我的 HTML 会包含 widthheight 属性

<img src="images/leopard.png" alt="Responsive images: Leopard on a tree branch" width="1000" height="667">

在 HTML 里包含 width and height 值是最好的做法。这确保了浏览器为图片保留了必要的空间,并且,当图片加载时,后续不会有页面回流。

基于此,我将用以下的 CSS:

img { 
  max-width: 100%;
  height: auto;
}

这些值会覆盖我的 HTML。max-width 属性被设置为 100% 是为了确保不管需要多少空间都会被填充,最大到 1000px(HTML 中的值)。height 值设为 auto 来确保图片的高度保持图片原有的宽高尺寸比例。如果我移除 height:auto 这一行,图片将会保持 HTML 中定义的高度,忽略了宽度,这通常是我不想要的。

你可以用 CodePen 试下这个简单的例子。如果你想要测试响应式能力,最好的方式是在一个新窗口打开这个 demo。

screenshoot

注意在我的例子中,图片的原始尺寸是 2000px x 1333px,但我选择最大为 1000px 展示它。

理论上,我可以在我的页面中用上面的方法,应用到每张图片,这也是一种基本的可接受的方式,在我的项目中实现响应式图片。但更理想地,我想让这个方法更加完善,控制图片分辨率以及其他因素,去提高性能并且帮助 SEO,这个我会在下面的章节讨论。

带有 srcsetsizes 属性的响应式图片

在上面的简单 CSS 例子中,我加载一个大约 1.44MB 大小的图片,这甚至是我用无损压缩图减小图片大小 之后的图片。这在桌面看起来还行,但是这肯定不是我想在小设备上加载的大小,像智能手机。这个时候 srcsetsizes 属性就派上用场了。

srcset 属性允许你在一个值中去指明多种图片大小。这将会是浏览器或设备在定义的情况下访问的图片。sizes 属性与 srcset 一起作用去告诉浏览器选择哪张图片。

这个是之前的例子中用多个不同版本实现的 leopard.png 图片:

<img srcset="images/leopard-480.png 480w, images/leopard-800.png 800w, images/leopard.png 2000w" sizes="(max-width: 600px) 480px, (max-width: 1000px) 800px, 1000px" src="images/leopard.png" alt="Leopard on a tree branch">

如果你之前从来没有见过 srcset and sizes 属性,这个可能在第一次看的时候会有点困惑。我会把它全部分解,这样会容易理解一点。

分解 srcset 属性

srcset 属性接受一个或多个字符串的的逗号分隔列表。每个字符串包含:

  • 一个指定图片的 URL
  • 下面其中一个可选修饰符(用空格分割):
    • 一个宽度修饰符
    • 一个像素密度修饰符

在我的例子中,我包含了宽度修饰符,这个是你将最常见的一个。我包含了三个不同版本的图片:一个高分辨率版本,和一个 800px 宽,还有一个 480px 宽。

注意,我在上面的例子中用的宽度修饰符,语法是宽度值后面紧跟着 “w”(不要用 “px” 单位值!)。对于每个表示图片的宽度修饰符,我用的是有固定像素宽度的图片。你可以用多种方式得到任何图片的真实大小,通过你的文件系统引用它的属性,一个图片编辑器,甚至在你的浏览器,用浏览器开发者工具。

分解 sizes 属性

sizes 属性只能和 srcset 属性一起,才起作用。你可以单独使用 srcset (看下一个章节),但是最常见的方式是,srcsetsizes 一起使用。

sizes 属性接收在一个或多个逗号分割的字符串列表。每个字符串包含。

  • 一个媒体条件(与媒体在 CSS 中查询使用相似)
  • 一个定义图片会占据插槽大小的值

插槽值可以是一个绝对长度像 em 或者 px 或者一个视口相关单位(例如 vw)。注意在我的例子中,在 sizes 属性的是插槽值,没有特别匹配三个宽度修饰符。下面是代码:

<img srcset="images/leopard-480.png 480w,
             images/leopard-800.png 800w,
             images/leopard.png 2000w"
     sizes="(max-width: 600px) 480px,
            (max-width: 1000px) 800px,
            1000px"
     src="images/leopard.png"
     alt="Leopard on a tree branch">

事实上插槽值没有精准匹配宽度修饰符是可以的。在我的例子中,我可以像这样分解 sizes 值:

  • 600px 宽的视口会从 srcset 值里面的 480px 宽,加载 480w 的图片。
  • 1000px 宽的视口会加载在 800px 插槽里面的 800w 图片。
  • 默认原始尺寸图片(2000w)会填充 1000px 插槽,如果前面的媒体条件没有匹配。

最后一个字符串是一个没有媒体条件的单独的插槽值。像提及的,着是确保浏览器会有东西展示,如果没有一个媒体条件匹配的话,会把这个当作默认值。

你可以查看例子代码,并用下面的 CodePen demo 起作用。注意在这个例子,你将不得不在模拟不同设备测试一些东西(像 Chrome 的开发者工具)。你也可以用多种真实设备打开一个页面去进行真实测试。为了方便,我会在每张图片上面包含一些文字,所以你可以在你看页面的时候知道那张图片加载了。

screenshot

注意在原始图片记载之后,在你改变视口的大小的时候,图片不会改变大小。srcsetsizes 属性在第一次加载的时候根据媒体条件加载图片时起作用,但在屏幕改变大小时不会起作用。后面,我会向你展示不同的响应式图片特性,这些特性会解决这个问题。

使用 srcset 和像素密度修饰符

在上面,我提及到 srcset 属性可以与像素密度修饰符一起使用。这个修饰符让浏览器根据设备的分辨力能力决定使用哪张图片。下面是一个例子:

<img srcset="images/leopard-480.png 480w,
             images/leopard-800.png 800w,
             images/leopard.png 2000w"
     sizes="(max-width: 600px) 480px,
            (max-width: 1000px) 800px,
            1000px"
     src="images/leopard.png"
     alt="Leopard on a tree branch">

注意这几件事。首先,对于常规的 src 属性,我用了最小的图片,确保优先移动端 处理。其次,srcset 属性包含了一些别的通过 1.5x 和 2x 修饰符指定分辨率的图片版本,480 图片不包含修饰符,因为被 1px 指明了。最后,注意没有 sizes 属性出现,因为我在这个例子中不需要,MDN 解释 浏览器是怎么选择图片的:

用户代理自行选择任何可用资源。这为他们提供了很大的自由空间,可以根据用户偏好或带宽条件来调整选择。

想理解修饰符是如何工作的,记住一个设备像素代表每个 CSS 像素。所以 1x 将是 1:1 比例,1.5x 将是 1.5:1 比例,以此类推。你可以在下面的 CodePen 试一试,但是你将不得不用不同的设备(或者用工具模拟他们)去看他们的不同。

screenshot

使用 <picture> 元素

至此为止,我讨论合并响应式图片的特性,都是假设我在不同的大小和分辨率展示同一张图片。虽然我在所有的例子中用 CSS 在用户调整浏览器大小时,改变图片的宽度,一旦页面加载了图片本身从没有真正改变过。

<picture> 元素是一个 HTML 特性,允许你根据特定媒体特性的出现提供可替代版本。这也允许用户在调整视口大小时切换图像,并允许你对图像进行美术设计,显示相同场景的不同类型,根据设备大小进行裁剪或缩放。

举个例子,在台式机或平板电脑的较大设备上拍摄一张中间有小物体的广角照片是合适的,但智能手机等较小设备可能会加载裁剪或放大的相同图像。

这是一些例子代码,允许我在我的图片中做些美术设计:

<picture>
  <source media="(min-width: 1000px)" srcset="images/chipmunk.png">
  <source media="(min-width: 800px)" srcset="images/chipmunk-zoom.png">
  <img src="images/chipmunk-closeup.png" alt="Chipmunk in a field on a rock">
</picture>

注意关于代码的内容:

  • <picture> 元素接受多个嵌套的 <picture> 元素,作为子元素
  • 每个 <source> 元素里面,<picture><media> 属性去定义触发使用该源图像的媒体条件
  • <picture> 元素接受常见的 &lt;img&gt; 元素作为子元素,如果浏览器不支持 <picture> 的话,会将其识别为备用方案。
  • <picture> 元素没有直接属性(<picture> 只接收 HTML 全局属性,并且它本身没有拥有任何属性)

下面的 CodePen 演示这个:

screenshot

如果你在一个新的窗口打开例子,你能调整窗口大小去观察图片的改变。注意图片对象如何在浏览器创建口变小时缩小。这是一种制作响应式美术设计图像的简单方法,无论你使用的是什么设备,它看起来都是合适的。当然,这需要更多的工作,但这是值得的,如果你想你的图像在任何设备使用是有意义的。

帮助响应式图片的工具和服务

有数不尽的可用免费商用工具,可以帮助实现响应式图片。有一些会帮助你避免写,我谈论的很多代码。这里是一些你可能有用的工具:

  • Responsive Image Breakpoints Generator – 简单生成最佳响应式图片的在线工具。
  • Images Responsiver – 一个 Node 模块将简单的 HTML 图片语法转换成更好的响应式图片语法。
  • gatsby-plugin-image - 一个 Gatsby 插件,处理制作多种尺寸和格式的图像的困难部分。
  • lazySizes - 一个快速的,免费的,SEO 友好的,并且自动初始化,懒加载图片(包括响应式图片 picture/srcset )iframes ,还有更多。
  • WURFL.js - JavaScript 检测智能手机,平板电脑,智能电视和游戏控制台的设备模型访问你的网站
  • Picturefill - 一个旧项目允许你用 <picture> 元素在更老的浏览器。我建议避免这个工具,因为它可能会膨胀你本来就在浏览器启动慢的代码。适当的回退技术或移动优先的方法可能更好。

重要且方便的是,许多不同的服务可以自动执行响应式图像,提供不同的图像大小、用于实时生成图像的API等功能。

甚至 WordPress 本身也内置响应式图片的支持(从版本 4.4 开始)。

另一个工具/服务值得调研的是 Optimole 。这是一个先进的图片优化和交付工具,由 Themeisle 的团队构建。这不仅会减少你的图像的磁盘大小而不影响视觉质量,而且还会通过图像CDN将图像传递给你的网站访问者。这个图片交付功能的一个方面是,你的图像也将优化,以便在不同的设备上观看。

有一个免费版本的 Optimole 可以用。它允许每月多达5000网站访问,并将给你所有的自动缩放功能,CDN,和更多。

你在网站中的响应式图片的经验是什么呢?在下面留言告诉我们把。