正在加载...

CSS 图像精灵

Optional Advanced 刚讲完 !important——罕见的覆盖旗帜。本课是另一项可选主题:图像精灵(image sprites)。你会在旧样式表和一些 legacy 图标集里见到它们。想法很简单:一张图文件,多枚图标;用 background-position 决定小窗口里露出哪一块。

直接回答

CSS 图像精灵是一张把多枚图标(或按钮状态)并排放在一起的图集。每个 UI 元素拿到固定的宽高、同一张 background-image,再用 background-position 滑动图集,直到目标块填满盒子。当年每枚图标都是一次 HTTP 请求时,精灵能减少请求数。新项目通常更宜用 SVG 图标、内联 SVG 或小型图标体系——只有在维护现有图集、或必须对齐 legacy 设计时,才继续用精灵。

精灵为何出现

多年前,每枚图标往往意味着又一次 HTTP 往返。把二十张小 PNG 合成一张图集,就是一次下载、一条缓存。浏览器再用 CSS 在图集上画出不同「窗口」。HTTP/2 与现代打包减轻了这种痛,可缩放的矢量图标通常也更清晰——但当你打开旧 CSS 时,定位这一套仍是有用的素养。

三块零件

你需要:

  1. 一张图集 — 例如按行或网格排布的 icons.png
  2. 一个盒子 — width 与 height 对齐单块(常用 display: inline-block 或块级链接)
  3. 一个偏移 — background-position,让正确的块落在盒子下
    background-repeat: no-repeat 防止图集平铺。你不是为每枚图标另载文件,而是用位置裁切。

共享图集上的第一块

设想每枚图标 32×32 像素,第一枚在左上。元素盒子也是 32×32,背景从 0 0 开始:

First icon tile from a shared sheet

css
.icon {
display: inline-block;
width: 32px;
height: 32px;
background-image: url("icons.png");
background-repeat: no-repeat;
background-position: 0 0;
}

盒子像视口。只有 icons.png 左上 32×32 可见。图集其余部分仍在——只是被元素尺寸裁掉了。

第二枚图标:滑动图集

若下一枚从图集右移 32px 处开始,就把背景向左移 32px(负 X)。同一张图、同样盒尺寸,不同窗口:

Second icon with a horizontal offset

css
.icon-home {
display: inline-block;
width: 32px;
height: 32px;
background-image: url("icons.png");
background-repeat: no-repeat;
background-position: 0 0;
}

.icon-search {
display: inline-block;
width: 32px;
height: 32px;
background-image: url("icons.png");
background-repeat: no-repeat;
background-position: -32px 0;
}

负 X 把图集往左拉,第二块填满窗口。第二行图标还会改 Y(例如 -32px -32px)。按真实图集测量——不要凭记忆猜偏移。

用另一块做 hover

按钮集常把默认与 hover(或 active)状态放在同一张图上。在 :hover 上只改 background-position:

Hover state from another sprite tile

css
.btn-icon {
display: inline-block;
width: 40px;
height: 40px;
background-image: url("btn-sheet.png");
background-repeat: no-repeat;
background-position: 0 0;
}

.btn-icon:hover {
background-position: -40px 0;
}

没有第二张图文件——只是另一次裁切。保持盒子尺寸稳定,控件才不会跳动。

平静的图集习惯

始终把图集与明确的盒子和 no-repeat 配对。类名按角色命名,而不是只写像素算术:

Named sprite roles and no-repeat

css
.sprite {
display: inline-block;
background-image: url("icons.png");
background-repeat: no-repeat;
}

.sprite--mail {
width: 24px;
height: 24px;
background-position: 0 -48px;
}

.sprite--bell {
width: 24px;
height: 24px;
background-position: -24px -48px;
}

在简短注释里记录块网格(块尺寸、行顺序),免得下一位维护者去反推魔法数字。

昔日精灵与今日图标

📊 Sprite sheets vs modern icon approaches

Approach Best when Watch out
CSS image sprite (PNG sheet) Legacy UI you must keep; one cached sheet already in the project Raster scales poorly; offsets break if the sheet changes
Inline SVG / SVG sprite Crisp UI icons at any size; easy theming with currentColor Slightly more markup or build setup
Icon font Very old stacks that already ship one Accessibility and ligature quirks; harder to theme than SVG
Separate PNG per icon Rare one-off graphics Many requests on old HTTP/1 connections
Real <img> photos Content images, galleries, product shots Not a job for background-position sprites

图像画廊与响应式图像课使用真正的 <img>(flex 缩略图、object-fit、srcset)。精灵通常是背景里的装饰性 UI 铬件——不能替代带有意义 alt 的内容照片。

新 UI 优先现代图标

全新界面请从 SVG 起步(内联或小型 SVG 精灵系统)。边缘更锐、换色更简单,也没有脆弱的像素偏移。只有设计包本身已是图集、或你在修补依赖该图集的 CSS 时,再找经典 PNG 精灵。

When a sprite is the wrong tool

css
/* Content photo — use <img>, not a sprite crop */
.hero-photo {
max-width: 100%;
height: auto;
}

/* UI chrome — sprite OK only if the sheet already exists */
.toolbar .icon-save {
width: 16px;
height: 16px;
background-image: url("legacy-toolbar.png");
background-repeat: no-repeat;
background-position: -64px 0;
}

自己动手试

  1. 在纸上画一行三枚图标(或打开真实精灵)。记下块宽(如 32px)。
  2. 建 .icon-a,设 background-position: 0 0 与匹配盒子。
  3. 加 .icon-b,用 -32px 0(或你图集的真实第二偏移)。
  4. 写一条 hover 规则,移到第三块且不改宽高。
  5. 在注释里写一句:这张图集为何仍存在(legacy),或下次为何改用 SVG。

常见错误

  • 把内容照片放进精灵,丢掉合适的 alt / 语义
  • 忘记 width 与 height,整张图集露出来或裁切不干净
  • 本该反向滑动图集却用了正偏移
  • 留下 background-repeat,块在盒子里重复
  • 新应用默认用 PNG 精灵,而不是 SVG
  • 从教程抄偏移,却没测量你自己的图集

小结

  • 精灵是一张图集;background-position 决定哪一块填满固定盒子
  • 历史上它减少了许多小图标的 HTTP 请求
  • 保持 no-repeat、稳定尺寸与角色命名;记录网格
  • 新 UI 优先 SVG(或类似方案);精灵留给 legacy 图集
  • 内容图仍用真正的 <img>——画廊与响应式图像是另一回事
  • Optional Advanced 下一课:多列(multi-column)

🧠 测试您的知识

准备开始

测试您的知识

通过这个互动测验挑战自己,看看你对这个主题的理解程度如何

❓
7
问题
🎯
70%
及格要求
♾️
∞
时间
🔄
∞
尝试次数

📝 说明

  • 仔细阅读每个问题
  • 为每个问题选择最佳答案
  • 您可以随时重新参加测验
  • 您的进度将显示在顶部