提高网站速度之图片技巧

30 Apr

网站的首页响应速度极其重要,这直接决定了新用户是选择留下还是选择放弃你的站点。有统计数据显示,用户的耐心通常<2秒。最好能让你的页面在2秒内呈现,起码部分呈现,否则时间越往后,你的站点被用户放弃的可能性越将指数级上升。

提高页面响应速度的需要考虑很多方面,其中非常重要的一项就是尽量减少HTTP请求的次数

通常网站会对脚本文件和CSS文件进行了合并处理,这样用户在第一次无任何缓存的前提下,(统计数据显示)访问米国排名前十的门户网站平均只会加载6-7个脚本文件和1-2个CSS文件。合并处理大大减少了HTTP请求的次数。那么图片呢?本篇将探讨一下如何技巧性地加载图片的方式以提高网站响应速度。

  • 图片内联
  • CSS Sprites
  • Image Map

图片内联

常见的加载图片的方式如:<img src=”img/25/1.jpg” />会导致一次HTTP请求,请求服务器回传图片。其实图片的本质也是数据,如果能直接获得图片的数据,就可以直接让屏幕绘制该图片,避免了HTTP请求。

获取图片数据可以用FileReader的readAsDataURL方法,你也可以参照HTML5 Doctor里关于生成图片预览的说明,原理都是一样的。

用JS写个小工具,代码其实没几行,如果懒得写。也有现成的工具站点如Encode Data URL(有兴趣可以查看该页面源码,同样是通过File API实现的,原理也是一样的),可以让你轻松获取图片的数据。获取到的数据被封装到了Data URL里,之后将Data URL传递给img的src或background-image的URL等属性即可实现图片内联。

例如将本地图片拖动到工具站点Encode Data URL里,自动生成的Data URL:

data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABg……U+LQ/9k=
  //data:image/jpg;为数据协议及类型名
  //base64为数据编码格式
  //后面一串就是经Base64编码后的图片数据了

将上面的Data URL直接塞入CSS端的img的src属性里即可:
<img src=”data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABg…U+LQ/9k=” />

现在浏览器可以直接显示图片,不必再通过HTTP请求和服务器交互了。而且因为是浏览器直接显示,规避了跨域的问题。

但图片内联也不是没有缺点的:

  • 比如图片一旦更新就需要同步更新CSS里Data URL的值,而用普通的图片加载方式的话,服务器端直接替换同名图片即可。
  • 比如Base64编码后数据大小会变大,因此将Data URL写入CSS后,CSS增加的大小会大于图片的实际大小。虽然CSS可以gzip压缩,而图片不能压缩,但庞大的CSS文件是不可取的。
  • 比如旧版本的IE6/7不支持(说真的,放弃它们吧)。

结合内联图片的优缺点,图片内联最好用于很少变更,且实际尺寸很小的图片。

CSS Sprites

CSS Sprites将多张图片合并成一张。所谓一图胜千言:

CSS Sprites

合并成一张图片后,原本多次HTTP请求减少为1次。加载后用background-position位置偏移来显示需要的图片。例如:

#navbar span {
  width:  31px;
  height: 31px;
  float:  left;
  background-image:url(/images/navbar.gif);
}
.nav1 {background-position:0 0; margin-right:4px;}
.nav2 {background-position:-32px 0; margin-right:4px;}
.nav3 {background-position:-64px 0; margin-right:4px;}
……

按常理合并图片后边缘处会有一些多余的空白部分,理应合并后尺寸变大才对。但出乎预料的是多张图片合并成一张后,合并后的尺寸要比多张图片加起来的尺寸要小。因为可以共享色表,而单独的一张图片会有单独的色表。

CSS Sprites的缺点主要是后期维护困难,一旦图片要发生变动,很容易导致CSS里位置重新计算偏移量。况且Photoshop切图合并也不是很容易的事。

因此CSS Sprites一般用于不常变动的背景,按钮,导航条,链接等地方。但如果图片太多,一张庞大的合并图可能是后期维护的恶梦。

Image Map

如上例用CSS Sprites合并成一张导航条图片后,还可以用Image Map。用<map>标签直接在一张图片上绑定多个连接,这样就不需要background-position位置偏移来显示图片了:

<img usemap="#map1" src="/images/navbar.gif">
<map name="map1">
  <area shape="rect" coords="0,0,31,31" href="nav1.html" title="nav1">
  <area shape="rect" coords="36,0,66,31" href="nav2.html" title="nav2">
  <area shape="rect" coords="71,0,101,31" href="nav3.html" title="nav3">
  ……
</map>

效果显然易见,如果你想在图片不同区域点击获得不同效果,可以告别请求多张图片并在页面端拼图的方式了。在本地处理合并好图片后,用Image Map可以有效减少HTTP请求数量。

总结

图片是网页不可或缺的一部分,而且加载图片通常比较吃带宽,对图片应该尽量用缓存和CDN来加快页面显示速度。但首次访问站点没有缓存或缓存过期时,上面3种方式(仅我所知)可以减少HTTP请求次数,并部分缩小图片尺寸,来加速页面的响应的速度。

Leave a Reply

Your email address will not be published. Required fields are marked *