目前手机等移动设备的网站开发已经有比较成熟的解决方案。一种是响应式网站,像笔者博客一样,PC 网站和移动网站使用同一套页面;另一种是把移动网站和 PC 网站分开,类似淘宝。
从网站 SEO 的角度来说,两种方式本身并没有明显的优劣,各有利弊。不论采取哪一种方式,都能够解决移动设备浏览的问题。
随着移动设备的类型越来越多,我们几乎不太可能针对某一类设备单独建设网站。不论 PC 网站和移动网站是否分开建设,都意味着网站将会面对越来越多具有不同屏幕尺寸、像素密度和显示能力的设备。也就是说,即使建设了单独的移动网站,我们仍然需要考虑网站如何适应不同设备的特性。

一般来说,网站比较容易实现自适应,笔者博客就是一个完全自适应的网站。但自适应网站有一个比较麻烦的问题,那就是图片。图片在网页中的重要性自然不必多说,那么在移动网站中,如何根据用户设备为用户提供合适的图片呢?
一般来说,有以下几种做法。
- 直接把质量最高的图片加入 HTML 中,用户使用不同设备访问时,再通过 CSS 或 JavaScript 控制图片大小。这种方式忽略了不同设备之间的差异,但可能因为加载了过大的图片而占用过多带宽,增加访问时间,也会消耗更多移动流量。
- 异步加载。首先在页面中加载一张较小的图片,再通过 JavaScript 获取用户设备信息,按需加载对应图片。这样可以减少首次加载的数据量,但实现起来比较复杂,也可能影响搜索引擎对图片内容的处理。
- 在 HTML 头部通过 JavaScript 生成一个 Cookie,包含设备分辨率、像素比等信息。在用户请求图片时,这个 Cookie 会和其它请求信息一起发送到服务器,服务端根据 Cookie 对图片进行处理,再传送给客户端。这种方式可以解决图片尺寸和优化问题,但灵活性较差,也可能因为用户不支持 Cookie 而导致工作失败。另外,在网页头部加入这种 JavaScript,总让人感觉有些奇怪。
为了解决移动开发中的响应式图片问题,HTML5 增加了 img 标签的 srcset 和 sizes 属性。
srcset 是由逗号分隔的一个或多个图像候选地址列表。每个候选项包含一个图片 URL,以及可选的宽度描述符或像素密度描述符。
宽度描述符使用 w 表示,例如:
demo-small.jpg 300w
像素密度描述符使用 x 表示,例如:
demo-medium.jpg 2x
w 和 x 不能同时用于同一个候选列表。
sizes 则用于告诉浏览器,在当前页面布局中图片预期占据多大的 CSS 像素宽度。当 srcset 使用 w 描述符时,浏览器会结合 sizes、当前视口以及设备像素比等信息,在候选图片中选择比较合适的资源。
如果 srcset 使用的是 x 描述符,而不是 w,那么 sizes 就没有作用。
这些概念读起来比较拗口,要彻底弄清楚,首先必须理解三个概念:设备 CSS 像素、设备物理像素、设备像素比。
如果对这三个概念不太清楚,可以查看之前的文章响应式网站建设中的像素和宽度问题。
理解了这些概念之后,还需要特别注意一点:
w 描述符并不是“设备物理像素宽度”,而是图片资源自身的固有像素宽度;x 描述符表示该图片候选资源对应的设备像素比。
例如:
<img src="demo-small.jpg"
srcset="demo-small.jpg 300w,
demo-medium.jpg 600w,
demo-big.jpg 750w">
这里的 300w、600w 和 750w 表示三个图片资源自身的宽度。
而下面这种写法:
<img src="demo-small.jpg"
srcset="demo-small.jpg 1x,
demo-medium.jpg 2x,
demo-big.jpg 2.5x">
则表示:
1x → 设备像素比为1时适合的图片
2x → 设备像素比为2时适合的图片
2.5x → 设备像素比为2.5时适合的图片
这里原文中 1px 应该写成 1x,因为 x 是像素密度描述符,而 px 是 CSS 长度单位,两者并不是同一个概念。
我们这里又遇到一个问题:为什么使用 w 描述符通常会比单纯使用 x 更灵活?
原因就在于,即使两台设备具有相同的设备像素比,它们的 CSS 像素宽度也可能完全不同。
例如有两台设备:
设备1:CSS像素宽度 720,设备像素比 2
设备2:CSS像素宽度 1024,设备像素比 2
现在有两张图片:
demo-small.jpg:360 × 200
demo-big.jpg:720 × 400
如果只使用像素比:
<img src="demo-small.jpg"
srcset="demo-small.jpg 1x,
demo-big.jpg 2x">
由于两台设备的像素比都是 2,它们都有可能选择 demo-big.jpg。
那么这张 720px 宽的图片,在两台设备上的 CSS 像素宽度分别大约是:
设备1:
720 ÷ 2 = 360 CSS像素
设备2:
720 ÷ 2 = 360 CSS像素
它占设备宽度的比例分别约为:
设备1:360 ÷ 720 = 50%
设备2:360 ÷ 1024 ≈ 35%
也就是说,即使两台设备的设备像素比完全相同,同一张图片在设备上的实际显示比例也可能完全不同。
这也是 w 和 sizes 组合使用的重要原因。
例如:
<img
src="demo-small.jpg"
srcset="
demo-small.jpg 360w,
demo-medium.jpg 720w,
demo-big.jpg 1080w
"
sizes="100vw">
这里告诉浏览器:图片预计占据当前视口的全部宽度,而 srcset 提供了不同宽度的图片候选资源。浏览器会结合当前图片需要显示的 CSS 像素宽度以及设备像素比,自动选择更加合适的图片。
这样,开发者就不需要直接根据某个具体手机型号判断应该加载哪张图片。
综上可以看到,使用 srcset 和相关描述符之后,浏览器能够根据当前客户端的实际情况自动选择合适的图片资源,实现按需加载和定向加载。
相对于文章开头提到的几种响应式图片方案,这种方式具有更好的灵活性,也能够在保证图片显示效果的同时减少不必要的流量,因此是响应式图片处理中更加标准的解决方案。
动态 Responsive Image 生成方案
srcset 方案有一个比较明显的问题,就是需要准备不同尺寸的图片。如果完全手工生成这些图片,费时费力。利用 Responsive Image 工具,可以根据请求动态生成图片。
基本使用方式如下:
- 下载代码,并把所有图片访问请求重定向到 Responsive Image 的
plm.php文件。 - 创建图片缓存目录,打开
plm.php,根据提示完成配置。 - 按照指定的 URL 格式生成图片。
例如:
裁剪:
example.com/example.jpg/(crop:[x[,y,]]width[,height])
缩放:
example.com/example.jpg/(reduce:[x[,y,]]width[,height])
括号中的内容表示具体操作,可以连续使用多次:
example.com/example.jpg/(crop:[x[,y,]]width[,height])/(reduce:[x[,y,]]width[,height])
表示先进行裁剪,再进行缩放处理。
其中 [] 内的参数为可选值。x、y 不填写时默认为 0,height 不填写时,裁剪操作默认使用图片本身的高度,缩放操作则使用等比例缩放后的高度。
具体可以参考 Responsive Image 中的 index.html 文件。
评论0
欢迎分享你的看法,也欢迎补充不同的实践经验。