个人总结:在当前响应式设计和自适应设计的流行下,很多web 应用往往都兼容手机、平板和PC,其中一个让人比较头痛的问题就是图片的加载了。不同平台显然不可能用同一张大的图片,这样子不但浪费手机流量、影响网站载入速度并且在小屏幕下会很不清晰。让浏览器根据分辨率自动识别图片是最好的方法。
响应式图片和多媒体是响应式网站的三大基础重点之一。表面上看这是一件非常简单的事情,只要把图片元素的高、宽属性值都移去,然后设置max-width属性为100%即可。不过在这么做之前还需要考虑很多情况。
设计响应式图片的难点
去年Filament Group在重构Boston Globe网站时也是通过设置max-width属性使得图片能够自适应。不过这么做的前提是你必须要创建一幅尽可能高分辨率的图片。
除非是真正需要那么大的图片,否则这就是一种浪费。智能手机和平板电脑通过移动网络浏览该网站时,并不需要那么大尺寸的图片——大尺寸图片意味着大的带宽。即使不考虑带宽也应该考虑同一幅图片以不同尺寸显示时的问题,在图片原始大小是300px的情况下以1000px尺寸显示无疑会损失很多的细节。最好的解决方法则是使用大图的一部分或者干脆完全用不同尺寸的图片。
同时我们不应当忘记高分辨率的显示需求。Apple 设备的retina技术显示图片要求更多的图片,考虑到其他设备也会跟随Apple的高分辨率显示技术(不过可能显示的像素尺寸不同)。我们若将所有不同尺寸的图片都预加载进来,此乃饮鸩止渴之举,万不可取——毕竟我们的目标只是是减少带宽而非增加。
我们需要更强大的能力为不同的设备环境提供合适的图片和多媒体。
3种解决方法
目前已经有几种备选的解决方案解决这些问题,Chris Coyier在他的博文里归纳总结如下:
- 创建一个新的(HTML)元素
- 创建新的图像格式
- 使用特定技术手段
下面我们一一简述各种方案。
创建新元素(或属性)
该方法已经在使用了,不过在使用方式上存在一些争议。这些争议主要来自两方面:业界的web开发者和浏览器制造者。web开发者提议创建一个新的picture元素(类似HMTL5中的video这样的元素),该元素中包含其他的图片源,示例代码如下:
<picture alt="image description"> <source src="/path/to/medium-image.png" media="(min-width: 600px)"> <source src="/path/to/large-image.png" media="(min-width: 800px)"> <img src="/path/to/mobile-image.png" alt="image description"> </picture>
其中的img元素是默认情况下显示的图片源,在其上面的两个source元素则是在特定媒体查询(media queries)条件下显示的图片——这也是开发者所喜欢的一种解决方案。
Scott Jehl针对图片元素创建了polyfill项目,就是利用了这种思想,你现在可是就可以使用它了。
<span data-picture data-alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia"> <span data-src="small.jpg"></span> <span data-src="medium.jpg" data-media="(min-width: 400px)"></span> <span data-src="large.jpg" data-media="(min-width: 800px)"></span> <span data-src="extralarge.jpg" data-media="(min-width: 1000px)"></span> <!-- Fallback content for non-JS browsers. Same img src as the initial, unqualified source element. --> <noscript> <img src="small.jpg" alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia"> </noscript> </span>
浏览器开发者则是通过给img元素标签增加srcset属性来解决此问题的,功能一样,然而直觉上不好理解。
<img src="path-to-default-image.jpg" alt="" srcset="path-to-default-image.jpg 600w 200h 1x, path-to-another-image.jpg 600w 200h 2x, path-to-a-third-image.jpg 200w 200h">
以srcset的一个值为例讲解:
path-to-another-image.jpg 600w 200h 2x
- path-to-another-image.jpg 是不言自明的,当符合下述条件时就使用该 图片
- 依据media queries要求,设备最小尺寸为600w和200h
- 浏览器有以2x像素密度显示的能力
因此这里所表达的意思是,当浏览器能够处理2x像素图片,且设备至少是600px宽、200px高的情况下,使用此图片源显示。此种解决方法从浏览器开发者角度看是非常合适的,毕竟能够让浏览器自己通过算法获取设备的兼容性和像素密度。
上述两种方法各有优点,此篇文章也并未认为其中一方的方法要好于另一方的。如何你想了解更多的讨论细节,可以点击链接。作为网站开发者我比较喜欢用picture元素,然而使用srcset属性的img元素有更强的兼容性。这场讨论现今仍在进行,大多数人希望能够找到一种吸取两者优点的方法。
这段时间我恰巧收听了一组讨论上述问题的播客,其地址如下:
- SitePoint Podcast #168: Secret Src with Jeremy Keith
- The Web Ahead: Responsive Images with Mat Marquis
创建新图像格式
这种方法更容易解释了,Christopher Schmitt 呼吁针对响应式图片创建一种新的图像格式。该新的格式包含了几种不同大小版本的图片。比如100k的文件里有75k的版本、20k的版本和5k版本的图像。
从某种意义上讲就像.mp3格式那样,该种文件格式既存储了歌曲也存储了歌曲的meta信息。这里的图像版本信息就好比MP3的meta信息,然后依据既定的一组标准选择该里面最为合适设备的一个图片版本。
这种解决方法的缺点是必须放弃一些可控性能。新文件格式会自行决定什么时候使用哪个版本的图片,只是当然对于不支持该种格式的浏览器也失去了后向兼容。
其他技术
上述的方法固然简单,然而面前还未正式标准。如果你想为不同的设备提供不同的合适图片,可以考虑使用下列多种方法之一。很多博文都将在一节篇幅中叙述所有这些技术。
我们可以模仿Filament Group的做法,他们针对Boston Globe网站提供响应式图片的做法如下:
- Markup —默认是用img元素标签
- Javascript — 决定viewport的尺寸,将存储在cookie中的相关信息传给服务器,而后再改变img标签的src属性。.
- Server — 获取初始图片请求,读取cookie,如果不是移动终端设备则返回1×1大小的空白占位图。然后等待JS脚本将真正的图片填充进去。
这种方式并没有想期望中那样完美,却也给出了一种解决思路,可以让其他人在上面继续发挥。
许多后续的方法其思路与此相仿,默认都是提供移动端图片,继而尝试探测设备属性后再发送合适大小的图片。
Chris Coyier 和 Christopher Schmitt创建了一张电子表格,你可以据此作为你项目中选用何种技术的参考。Chris也基于这张电子表格写了一篇技术文章回答大多数疑问——你应当使用哪种自适应图片技术?我在上面所提及的技术也许给你一些大概的印象,你不妨看看Chris的那篇文章和电子表格,以了解这些技术的细节实现。
Foresight.js是在给服务器发送请求之前用JavaScript去探测该设备是否支持高分辨率图片,同时也探测该设备所在网络的网速。依据探测结果才向服务器请求合适的图片资源。
Images redux使用空白的1x1GIF(转成base64格式)。它将该图片设置为所有图片的初始背景或占位符,提供更好的用户体验。由于图片是依据CSS设置的,所以可用media queries改变响应样式。
Image above via CSS Tricks
Adaptive images 项目灵感来源于Filament Group重构Boston Globe网站的工作。不过它需要诸如Apache 2, PHP 5.x, 和 GD 库等的支持,好在这些工具都比较常用。该技术首先在cookie中保存屏幕分辨率,然后决定使用哪种合适的图片尺寸。如果JavaScript和cookie被禁用了,它就检测user agent字符串。如果发现“mobile”字符,就发送最低分辨率(定义在$resolutions里)的图片给终端,否则就默认假设你使用大设备终端并发送高分辨率图像。
HiSRC是一个jQuery插件,它能探测网络速度与分辨率,默认情况下只提供最小的图片。但是HiSRC能够探测设备更多的能力,然后提供更多不同类别的图像。
Jeremy Keith在文章里提出Conditionally Loading Content的方法,也是关于如何向不同设备提供不同图像。由于探测了viewport的宽度,Jeremy其实是提供了自定义的解决方案。Jeremy在后续的文章中也提出了Conditional CSS方法,展现了如何在前人的基础上进行改进的方案。
总结
图片响应式化的第一步是让它自适应,移除高、宽属性然后设置max-width属性为100%。然而这并不能从根本上解决问题。主要的问题在于,那样做会不得不创建一张大尺寸高分辨率的图像,很明显这种图片并不利于移动终端设备的接收。
一种有效的解决方法是使用新的HTML语法,告知浏览器应当使用那张合适的图片;也许我们应当创建新的图像格式,那样也能解决现在的问题。
不过为今之计,还是不得不借助现有的技术实现图像响应式。这些技术的思想是提供移动端版本的图像,然后探测其是否还能处理更大的图像,如果可以则使用Javascript脚本将更大的图片替换默认的小图。
图片响应式和响应式设计其实还有很长一段路要走,我还会继续就这个话题展开叙述,下次应该主要涉及矢量图像方面的内容,由于这方面的内容和此篇文章主题关系甚微,所以就单独展开。
本文的最后,就给出Jason Grigsby一系列关于响应式图片的博文,希望大家喜欢。