CSS Sprites:鱼翅还是三鹿?

原文:CSS Sprites: Useful Technique, or Potential Nuisance?

译文:CSS Sprites:鱼翅还是三鹿?

无处不在的 CSS sptites - 为数不多的几个可以直接跳过”流行”这个过程,而可以马上并且牢牢地跻身于最佳 CSS 实践之中的几个技术之一。虽然它真正流行是在 A List Apart 解释并认可这个技术之后,但是早在 2003 年 7 月份,Peter Stanicek 就已经开始谈论它了。

目前大多数的开发人员对这个技术都有相当地掌握,也有很多关于它的教程和文章。几乎所有的文章中都宣称设计师和开发人员都应该使用 CSS sprite 来减少 HTTP 请求数,并且节省一些流量。这个技术被大量网站使用,包括使用了大型 sprite 的 Amazon .

但是这些被广泛热议的好处真的是值得的吗?设计师们是否在没有全面考虑到所有情况的情况下,在盲目地使用这个技术呢?设计师们是不是过于关注 CSS sprite 的流行,而忽略了其它应该仔细斟酌的因素了呢? 这篇文章会讨论下使用 CSS sprite 的好处和坏处,尤其关注”滥用” sprites 的情况,而且会解释下为什么“滥用” sprite 其实是浪费时间。

浏览器缓存所有图片

sprite 技术的其中一个好处是图片的加载时间(在有许多 sprite 时,单张图片的加载时间)。由所需图片拼成的一张 GIF 图片的尺寸会明显小于所有图片拼合前的大小。单张的 GIF 只有相关的一个色表,而单独分割的每一张 GIF 都有自己的一个色表,这就增加了总体的大小。因此,单独的一张 JPEG 或者 PNG sprite 在大小上非常可能比把一张图分成多张得来的图片总尺寸小。但是这真的有想象的那么好吗?

一般来说,浏览器会缓存所有的图片 – 无论图片 sprite 与否。sprite 技术只是在页面第一次加载的时候才会节省带宽,同时缓存也会对使用相同图片的其他页面有效。

Firefox 缓存显示的浏览器缓存的来自 amazon.com 的图片(在 Firefox 地址栏输入 “about:cache” 来查看)。

考虑到现在的普遍网速已经比 2003-2004 年时提出这个技术的时候要快多了,因此大量使用 sprite 技术就不是那么必要了。有一点需要明确,不是说不应该用 sprite,而是不应该为了有限的好处来滥用这个技术。

拼合图片的时间成本会增加

想象一下一个有三个状态的图片按钮是怎么制作的:代表不同的状态的图片需要临近放置在一起组成一张图片。在使用 Photoshop 或其他软件切图时,不同的状态并不会在一起;需要把他们单独切出来再合并为一张图片。

如果其中任一个图片状态需要改变,整个图片就需要重新制作保存。对一些设计师来说这不是什么问题,也许他们会单独保留不同按钮状态的源文件,这样需要合并的时候就简单了。但是这个过程有点复杂,远没有切出一个单独图片来的简单。

为了节省几 k 的流量和几个服务器请求(还只发生在第一次加载页面时),sprite 技术是否真的值得?

编码和维护的时间成本会增加

图片切片输出之后,麻烦依然存在。虽然习惯这个过程之后,按钮 sprite 可以很简单地编码到 CSS 中,但是其他的 sprites 就不这么简单了。

单一的一个按钮一般会是个有定宽的

    元素。假如按钮的 sprite 是彼此独立的,就比较简单:
      的宽高会和列表项和锚点的宽高一致,每个状态的 sprite 对齐摆放。sprite 的位置也可以很容易地根据每个按钮的宽高计算出来。

      但是遇到之前提到的,像 Amazon 或者 Google 用到的大型 sprite 的情况时,会怎么样呢?你能想象到到维护这么一个文件,并且在 CSS 中改变 sprite 项的位置会是什么样吗?还有第一次创建 CSS 代码的情况?相对于一个可以轻松计算出来状态位置的简单按钮来说,大型的 sprite 会导致无尽地测试和图片状态的重新摆放。

      一些用于定位 Google 的 sprite 图片的样式

      Amazon 的 sprites 确实节省了至少 30 个 HTTP 连接,性能方面也确实有了很大的提高。但是把这些好处拿来和开发以及维护成本做个比较,再把缓存和网速等因素考虑进来,决定使用如此大型的 sprites 也许就不那么令人信服了。

      Sprites 是否真的需要“维护”?

      当然了,有些人不觉得 sprite 是首要引起头疼的问题。大部分情况下,一个 sprite 创建并编码完之后,就很少会被改动了,也不会受进行中的网站维护的影响。假如你感觉 sprite 维护不是个问题的话,那么也许使用大型 sprite 是最好的选择。

      不是所有图片都是背景

      另一个不提倡滥用 CSS sprite 的理由是这会导致开发人员错误地使用背景图片。有经验的开发人员会在项目中考虑可访问性问题,他们明白并不是每个图片都是背景。背景图片应该留给按钮以及用来装饰元素,而用来传达重要信息的图像应该内联在 XHTML 中。

      Amazon 正确是使用了内联图像元素和装饰用的背景。

      错误得使用 Sprites 影响可访问性

      一些刚入门的开发人员会为了节省 HTTP 请求数(这是使用 CSS Sprite 一直强调的好处)而把所有的图片都当背景图片来处理 – 甚至是那些传达重要信息的图片。结果会导致一个缺乏可访问性的网站,也会降低 HTML 中 title 和 alt 的潜在益处。

      因此,CSS sprite 本身没错,而且也不会引发可访问性问题(事实上,正确得使用会提高可访问性)。但是不分对错得过度使用 sprite 会阻碍具有可访问性和生产率方面的网页建设进程。

      HTTP 请求数又如何?

      许多人会据理力争,改善网站性能最重要的部分就是减少 HTTP 请求数。也要知道一项研究表明一个网站日常的访问者中 40-60% 比例都是没有浏览器缓存的。这是否足以说明应该在所有情况下使用大型 sprites 呢?或许是这样。尤其是考虑到用户的首次来访对一个网站的重要性。

      Firefox 的 YSlow 插件显示 HTTP 请求数

      以往的浏览器一般只允许 2 个并发 HTTP 连接,3.0 版本以来的 Firefox 和 IE8 默认允许 6 个并发 HTTP 连接。这意味着每台服务器有 6 个并发连接。引用 Steve Souders 的话:

      “明白这是服务器的基础是很重要的。使用多个域名,如 1.mydomain.com, 2.mydomain.com, 3.mydomain.com, 等等,使开发人员可以完全利用服务器连接数。在所有域名是同一 IP 地址的 CNAME 时依然有效。”

      因此,或许在按钮状态之外使用 CSS sprites 也是有益的,在未来,随着网络连接速度的加快和新版浏览器的性能提升,使用大型 sprites 所带来的好处将会变得不值一提。

      那些 Sprites 生成器呢?

      另一个喜爱大型 sprite 的理由是可以利用一些 sprite 生成器来简单得生成 sprite。对此类工具的详细讨论和评测不在本文讨论范围。但是从作者对此类工具的研究来看,帮助非常有限,并且维护这些 sprites 一样需要可观的工作量,这也是需要和收益权衡的。

      有些工具,例如来自 Fondue 项目的这个,提供输出 CSS 选项。Steve Souders’ 的工具 SpriteMe 是另一个提供 CSS 编码选项的。SpriteMe 会把现有的网站背景图片转换成单张 sprite 图片(我之前提到的“大型” sprite)并提供下载以供编码入页面之中。然而这些工具只是有助于创建 sprite,并不能在维护方面提供多少帮助。Souder 的工具貌似对重新设计或布局的网站无效,而且只对那些现有的没有使用 sprite 方法的网站有用。

      可以改进现有的工具,而且未来也会有新的工具出现。但是,鉴于以上提到的这些缺点,是否还存在这种可能,就是开发人员依然把精力集中在有限的所得上?

      关注多个性能提升点

      上面提到,HTTP 请求数是提升网站性能需要考虑的一个非常重要的因素。但是有别的方法可以减少连接数,包括合并脚本和样式表,使用远程库文件(即使用 Google 或者 Yahoo!提供的库文件托管)。

      除了 HTTP 请求数之外还有很多开发人员可以关注的用于提升网站性能的因素。包括服务器启用 Gzip,正确的放置外链脚本,优化 CSS 语法,压缩较大的 JavaScript 文件,提升 Ajax 性能,避免使用已知的会引起性能问题的 JavaScript 语法,等等。


      YSlow 显示了 HTTP 请求数之外可以提升网站性能的因素

      如果开发人员花点时间来考虑下所有可以提升网站性能的因素,再权衡下利弊,也许就有较好的理由可以避免滥用 CSS sprite 了,并且会把精力放在那些物有所值的方面。

      总结

      请不要误解我所说的。许多顶级的 blogger 和开发人员已经称颂 sprite 的好处很多年了,最近几年又把这些意见推广到使用大型 sprite 上来了 – 因此应该认真得考虑下这些观点。但是,这种有着完善的体制和系统,使得网站维护任务简化并流水化的公司,并不是所有人都能进去的。大多数人都是独立工作,或者接受别人创建的项目。这类情况下,大型的 sprite 会导致得不偿失的麻烦。

      糖伴西红柿的总结

      标题有点醒目 :) 原标题的规矩翻译为 CSS Sprites:有用的技术还是潜在的麻烦?

      关于 CSS Sprite,在 Web 标准交流会 第二期的时候讨论过。其实 CSS Sprite 是很有用处的。但是前提是不要超出一个度的限制。基本上很多问题最终都会归于如何适度地使用的问题。老话说:过犹不及,其实还是很有道理的。

      对于减少 HTTP 请求数问题,可以稍作妥协,把图片分类,尽量把内容固定、后期不会有太多变动的图归入一个 sprite 中,例如一些 icon 。那些会经常改动的图片归入一类,分成几组 sprite。对于设计花哨而生命周期很短的专题来说,真得,花费在拼图上的时间和经历实在是有点浪费了。

      关于老外的文章,我现在觉得有些絮叨了。或许很多人也会有这个感觉。其实应该反思下,据说日本有专门的小册子来教人做一些非常基础的东西,内容步骤细致到令人发指得地步。基础的东西大多人会不屑一顾,觉得别人都谈论奇技淫巧、高级应用了,我还在搞这些基础,多丢人啊。

      基础的东西其实没那么简单的,有谁能真得掌握了这些看上去简单的基础呢?看一下这个基础问题你真的了解HTML吗?

      曾经有一个高手送我一本书,他写了 ”Back to basic“ 送我,我在这里送给大家,希望大家都能踏踏实实地努力进步。