响应式图片规划

Avatar of Chris Nwamba
Chris Nwamba

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 $200 免费积分!

我第一次制作响应式图片时,代码很简单,只有四行

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

虽然这对开发人员来说足够了,但对用户来说并非最佳选择。如果 src 属性中的图片很重怎么办?在我的高性能开发设备(像我 16GB 内存的设备)上,几乎没有或不会出现性能问题。但是,在低端设备上呢?情况就不一样了。

image at multiple screen sizes

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

如今,最便宜的 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 的响应式图片指南,第 123 部分。

查看下面的代码示例。

<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 的推文直观地解释了发生了什么

当我第一次尝试分辨率切换时,我感到困惑并发了推文

向 Jason Grigsby 在回复中做出的澄清表示敬意。

由于分辨率切换,如果浏览器大小发生调整,它就会为正确的视窗下载正确的图像;因此,对于小型手机(对 CPU 和 RAM 有好处)使用小型图像,对于较大视窗使用较大图像。

上表显示,浏览器以不同的磁盘大小(红色矩形)下载相同的图像(蓝色矩形)。

查看代码笔
网格画廊 [优化]
由 Chris Nwamba (@codebeast)
CodePen 上。

Cloudinary 的开源且免费的 响应式图像断点生成器 对于将网站图像适应多个屏幕尺寸非常有用。但是,在许多情况下,仅设置srcsetsizes就足够了。

结论

本文旨在为在许多(且可能令人困惑的)可用选项中设置响应式图像和布局提供简单但有效的指南。请熟悉 CSS 网格、艺术指导和分辨率切换,您很快就会成为忍者。继续练习!