网站上一堆小图标(社交媒体按钮、导航箭头、状态标志)如果各自存成单独的图片文件,浏览器加载页面时就要为每一张小图单独发一次请求——CSS Sprites 把这些小图合并成一张大图,用坐标定位代替文件请求,减少的正是这部分网络开销。
浏览器渲染网页时,每引用一张图片资源(<img> 标签或 CSS background-image),都需要向服务器发起一次独立的 HTTP 请求去获取这个文件。在早期的 HTTP/1.1 协议下,同一个域名下浏览器能同时并发的连接数是有限的(通常 6-8 个),如果一个页面上有几十个小图标,即便每个文件体积都很小,累积起来的请求数量本身(每次请求都有 TCP 握手、HTTP Header 传输等固定开销)就会成为拖慢页面加载速度的瓶颈——这不是"数据量大"的问题,而是"请求次数太多"的问题。
CSS Sprites 的做法是把这些原本零散的小图标,提前拼接合并成一张大图,页面上只需要加载这一张合并后的图片文件——发起一次网络请求,就能拿到所有图标需要的像素数据。每个具体图标怎么显示,靠的是 CSS 的 background-position 属性:给元素设置这张合并大图作为背景,再指定一个精确的偏移坐标,让浏览器只"露出"这张大图里对应图标所在的那一小块区域,视觉上看起来就和单独加载这个小图标完全一样。这个原理和"精灵表"(游戏开发里把角色的多帧动画图片拼接成一张大图)在技术思路上是完全一致的——都是"合并存储、按坐标裁切显示"。
CSS Sprites 这套技巧诞生并流行于 HTTP/1.1 时代,核心解决的正是"HTTP/1.1 并发连接数有限、请求数量本身开销大"这个问题。HTTP/2 引入了多路复用(同一条连接上可以并行处理多个请求,不再受限于少量并发连接数),这在一定程度上削弱了"减少请求数量"这件事本身的收益——理论上 HTTP/2 环境下,加载多张小图和加载一张合并大图的性能差距,比 HTTP/1.1 时代要小得多。不过 CSS Sprites 依然有其它现实价值:合并成一张图之后,图片压缩算法能利用图与图之间的相似性做更好的压缩,总体文件体积往往比多张小图分别压缩的总和更小;同时对于图标数量特别多、且需要兼容老旧 HTTP/1.1 环境的项目,这个技巧仍然是一个有效的性能优化手段。
在线工具:精灵图生成