CSS 精灵图指南 - 创建和优化图像精灵表
什么是 CSS 精灵图 - 将多张图像合并为一张
CSS 精灵图将多个小图像 (图标、按钮、装饰元素) 合并到一张大图中,通过 CSS background-position 显示特定区域。这减少了 HTTP 请求数量,在 HTTP/1.1 时代是重要的性能优化手段。
名称的由来:精灵图 (sprite) 一词来自游戏开发中的「精灵表」。从任天堂红白机、超级任天堂的时代起,把角色的各个动画帧集中放在一张图上就是标准做法,Web 开发沿用了这个概念和名称。
工作原理:元素设置固定宽高,背景图为精灵表,通过负的 background-position 值将目标图标移动到可见区域。
历史背景: HTTP/1.1 下浏览器对同一域名的并发连接数有限 (通常 6 个),大量小图像会导致请求排队。假设页面上有 30 个图标,单独加载就需要 30 次请求;合并为精灵表后只需 1 次。精灵图将数十个请求合并为一个,显著提升加载速度。
现代意义:随着 HTTP/2 和 HTTP/3 的普及,多路复用 (multiplexing) 减少了合并请求的必要性,但精灵图在特定场景 (游戏、大量图标) 仍有价值。具体收益有三点:一是省去每个文件各自的开销 (请求头、TLS 握手);二是浏览器缓存的命中效率更高,一个文件的缓存策略比几十个文件更容易管理;三是合并后的总体积往往小于各文件之和 —— 图标集这类色调和尺寸相近的图像,放在一张图里压缩时冗余更容易被消除,压缩率的提升尤其明显。此外还能减少 DNS 查询和连接建立的开销。
精灵表设计原则 - 高效布局策略
精灵表的布局直接影响文件大小和使用便利性。如果毫无规划地排列图像,CSS 会变得冗长难读,日后追加或替换图标也会很痛苦。
布局策略:
- 网格布局:所有图标统一尺寸,等间距排列。坐标计算简单 (偏移量都是
-Npx -Mpx这样的规则值),可维护性最高,适合 16x16px、24x24px、32x32px 等统一规格的图标集 - 紧凑布局:不同尺寸的图标紧密排列,最小化空白。通常借助装箱 (bin packing) 算法把整张图压到最小。文件更小但坐标复杂,实际上必须配合自动生成工具使用
- 分类布局:按功能分组 (导航图标一行,社交图标一行)。便于维护,也能避免让只在某个页面用到的图标被所有页面加载
间距设计:设计上的要点是确保余白 (padding)。
- 图标间留 1-2px 间距防止相邻图标渗透 (子像素渲染)。特别是用
background-size缩放时,没有间距会让相邻图标的边缘露进来 - 为 Retina 屏幕准备 2 倍尺寸的精灵表并缩小显示时,建议把间距放大到 2-4px
- 过大间距浪费空间,过小可能出现边缘伪影
尺寸考虑:
- 精灵表总尺寸控制在 2048x2048 以内 (移动设备限制)
- 宽度为 2 的幂次有助于 GPU 纹理处理
- 考虑 Retina 屏幕:提供 2x 版本
为扩展留出余地:在图的右侧或底部预留一块空白,日后追加图标时就不必改动既有图标的坐标,CSS 的改动量能降到最低。
精灵表创建 - 工具与工作流
精灵表的制作分为用图像编辑软件手工排版和用工具自动生成两种。根据项目规模和图标的更新频率来选择。
构建工具集成 (推荐):
- webpack-spritesmith: Webpack 插件,自动从图标目录生成精灵表和 CSS/SCSS。支持 HMR (Hot Module Replacement),开发中新增图标会自动重建精灵表
- gulp.spritesmith: Gulp 任务,监听文件变化自动重建。spritesmith 本身是 Node.js 的精灵图生成库,只要把图片放进指定目录,就会同时产出精灵表和配套的 CSS/SCSS
- postcss-sprites: PostCSS 插件,自动将 CSS 中引用的小图合并。由于不需要改写既有的
background-image声明,把它引入到遗留项目里很容易
命令行工具:
- spritesheet-js: Node.js 工具,支持多种布局算法
- ImageMagick montage:
montage icon*.png -geometry +2+2 sprite.png
在线工具:
- SpritePad:拖拽式在线精灵表生成器
- CSS Sprite Generator:上传图像自动生成
手工制作 (小规模项目):在 Figma 或 Photoshop 里建立画板,沿网格摆放图标,导出时根据内容选择 PNG-8 (256 色以内的图标) 或 PNG-24 (含渐变的图标)。坐标需要手写进 CSS,因此图标超过 20 个就该转向自动生成工具。
输出格式:工具通常同时生成精灵表图像和 CSS/SCSS/JSON 坐标文件。坐标文件记录每个图标的位置和尺寸。
SVG 精灵 (现代的替代手段):矢量格式的图标适合用 SVG 精灵。以 <symbol> 元素定义各个图标、用 <use> 元素引用。与 CSS 精灵不同,颜色和尺寸都能用 CSS 自由改变,也不需要单独适配 Retina。可以用 svg-sprite 或 svgo 等工具自动生成。
CSS 实现技巧 - 掌握 background-position
正确使用 CSS 属性显示精灵图中的特定图标。基本思路是:用一个公共类指定精灵表,再用各自的类指定坐标和尺寸。
基本用法:
.icon { display: inline-block; width: 24px; height: 24px; background-image: url('sprites.png'); background-repeat: no-repeat;}.icon-home { background-position: 0 0; }.icon-search { background-position: -24px 0; }.icon-user { background-position: -48px 0; }
Retina 适配:准备 2 倍 (或 3 倍) 尺寸的图,再用 background-size 缩小显示。例如要让 24x24px 的图标适配 Retina,就用 48x48px 绘制精灵表,并指定 background-size: 原始图宽的一半 auto;。
.icon { background-image: url('sprite@2x.png'); background-size: 200px 100px; /* 原始尺寸的一半 */}
SCSS/Sass 的效率化:把坐标管理抽象成变量和 mixin,可维护性会大幅提升。常见做法是用 $icon-home: 0px 0px 24px 24px; 这样的变量记录坐标与尺寸,再由 mixin 展开。spritesmith 也支持直接生成 SCSS 模板。
@mixin sprite($x, $y, $w, $h) { width: $w; height: $h; background-position: -$x -$y;}
悬停与激活状态:把常态和悬停态的图标放进同一张精灵表,用 :hover 伪类切换 background-position。这样悬停时不需要再去加载新图像,可以避免首次悬停时的闪烁 (FOUC)。
精灵图优化 - 减小文件大小提升速度
仅仅做出精灵表还不够。要真正拿到性能收益,还需要在文件大小和显示速度上继续优化。
格式选择:
- PNG-8:图标颜色少于 256 色时,比 PNG-24 小 60-80%。透明只能表达为 1 bit (全透明或全不透明)
- PNG-24/32:含渐变或半透明的图标使用。文件更大,但能保住画质
- WebP:支持透明,比 PNG 小 25-30%。浏览器支持率已超过 97%,可以积极采用,但仍需用
<picture>或 CSS 的image-set()准备回退 - SVG 精灵:矢量图标的最佳选择,无限缩放
压缩优化:
- pngquant:有损 PNG 压缩,视觉差异极小。
pngquant --quality=65-80 sprites.png减色后,再用optipng -o7 sprites.png二次优化,两者组合通常能减掉 40-70% - oxipng:无损 PNG 优化
- 减少颜色数:图标通常不需要完整的 24 位色彩
减少空白:
- 使用紧凑布局算法最小化图标间空白
- 裁剪图标周围的透明边距。图的右端或底部留有大片空白时,整张图的体积会被白白撑大
- 考虑将不同尺寸的图标分组到不同的精灵表
- 但如果是为了日后追加图标而有意留白,就跳过这一步
缓存策略:在文件名里加入哈希 (sprites.a3f2b1.png),就能一边设置长期缓存 (1 年),一边保证更新后必定分发新文件。Webpack 的 [contenthash] 和 Vite 的资源哈希都能做到这一点。
CSS 精灵图的现状与替代方案 - 2026 年的正确选择
CSS 精灵图在 2010 年代前期达到鼎盛,在现代 Web 开发中其必要性已大幅降低,但在特定场景仍有价值。
现代替代方案:
- SVG 图标系统:使用
<symbol>+<use>的 SVG 精灵,写作<svg><use href="#icon-name"></use></svg>。矢量、可着色、可动画,不依赖分辨率所以无需 Retina 版本。在无障碍方面也更容易用aria-label或<title>赋予语义 - 图标字体: Font Awesome、Material Icons 等,用
color和font-size就能改样式,很省事。但存在屏幕阅读器误读、子像素渲染发虚、无法表达多色图标等制约,新项目正逐渐被 SVG 取代 - 内联 SVG:直接在 HTML 中嵌入 SVG。最灵活但增加 HTML 大小
- CSS 图标:纯 CSS 绘制简单图标。无额外请求
HTTP/2 下直接分发独立文件:多路复用让大量小文件也能高效分发,直接提供独立的 PNG/SVG 已不再像 HTTP/1.1 时代那样吃亏。不过文件数超过 100,或特别看重首次访问的性能时,精灵图和打包依然有效。
仍适合使用精灵图的场景:
- 大量位图图标 (非矢量),比如照片风格的图标和复杂插画
- 游戏和动画 (帧动画精灵表),以及地图应用这类基于瓦片的显示
- 需要支持极老浏览器 (IE 11) 的项目
- 图标数量极多 (100+) 且为位图格式
- 既有精灵表已稳定运行,迁移成本不划算
决策建议:截至 2026 年,新项目应把 SVG 精灵作为第一选择,只在确实需要位图时才考虑 CSS 精灵图;简单图标考虑纯 CSS 实现。HTTP/2 环境下,少量独立小文件的性能损失已可忽略。