CSS 雪碧图:它们是什么、为什么很酷以及如何使用它们

Avatar of Chris Coyier
Chris Coyier 发布

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

本文自 2007 年首次发布以来,经过多次修订和重写,以保持信息的最新性。最近一次修订由 Flip Stewart 于 2015 年 1 月完成。

什么是 CSS 雪碧图?

剧透警告:它们不是帮你编写样式表的仙女。我希望如此。简而言之:CSS 雪碧图是一种将多个图像组合到单个图像文件中的方法,以便在网站上使用,从而提高性能。

考虑到您创建的是一个大图像而不是使用许多小图像,所以“雪碧图”这个词似乎有点用词不当,但是可以追溯到 1975 年的 雪碧图的历史 应该有助于澄清这些问题。

概括地说:“雪碧图”一词源于计算机图形学中的一种技术,最常用于视频游戏中。其想法是计算机可以将图形提取到内存中,然后一次只显示该图像的一部分,这比不断提取新图像要快。雪碧图就是那个大型的组合图形。

CSS 雪碧图的原理与此完全相同:获取图像一次,然后将其四处移动,只显示其一部分。这样可以减少获取多个图像的开销。

为什么要使用 CSS 雪碧图?

将较小的图像塞进较大的图像中似乎违反直觉。较大的图像加载时间不会更长吗?

让我们看看实际示例中的一些数据

图像 文件大小 尺寸
canada.png 1.95KB 256 x 128
usa.png 3.74KB 256 x 135
mexico.png 8.69KB 256 x 147

这加起来总共需要加载 14.38KB 的三个图像。将这三个图像放到一个文件中,重量为 16.1KB。雪碧图最终比三个单独的图像大 1.72KB。这并没有太大区别,但是**必须有充分的理由接受这个更大的文件……并且确实有!**

虽然雪碧图的总图像大小(有时)会增加,但**多个图像使用单个 HTTP 请求加载**。浏览器限制站点可以进行的并发请求数量,并且 HTTP 请求需要 一些握手过程

因此,雪碧图对于 与压缩和合并 CSS 和 JavaScript 相同的原因 非常重要。

如何使用 CSS 雪碧图?

这是一个雪碧图示例,其中将三个不同国家的国旗组合到单个图像中

您可以在多个 CSS 类中设置相同的 background-image,并设置各个类的背景位置和尺寸以显示雪碧图的一部分。以下是一些演示该概念的代码

.flags-canada, .flags-mexico, .flags-usa {
  background-image: url('../images/flags.png');
  background-repeat: no-repeat;
}

.flags-canada {
  height: 128px;
  background-position: -5px -5px;
}

.flags-usa {
  height: 135px;
  background-position: -5px -143px;
}

.flags-mexico {
  height: 147px;
  background-position: -5px -288px;
}

如果您认为必须有一种方法可以自动化此过程,以便您无需手动创建这些雪碧图,然后调整样式表以匹配,那么您是对的,并且您很幸运!

使用 Grunt/Gulp/Node 生成雪碧图

如果您通常使用 Grunt、Gulp 或 Node,则 css-sprite (现在称为 sprity) 是一个很棒的 Node 包,它可以从图像的 glob 中创建雪碧图。Sprity 具有许多很棒的功能,包括将输出格式化为 PNG、JPG(或 Data URI)以及以 CSS、LESS、Sass 和 Stylus 生成样式表。

要通过命令行编译雪碧图,请使用以下命令全局安装 css-sprite:

$ npm install sprity -g

然后,要生成雪碧图和相应的样式表,请运行:

$ sprity ./output-directory/ ./input-directory/*.png

有关在 Grunt 或 Gulp(或许多其他环境)中使用 css-sprite 的更多信息,请访问 GitHub 上的项目存储库

使用 Compass 生成雪碧图

使用 Compass 生成雪碧图 需要一些额外的设置和维护,但是如果您已经在使用 Compass,它可以很好地融入您的现有工作流程。

首先在您的 `images` 目录中创建一个目录(是的,它需要位于您的 `images` 目录中才能工作),并使用与您要创建的雪碧图相对应的名称。确保您要转换为雪碧图的图像为 PNG,并将它们放在您的新目录中。我正在创建国旗雪碧图,因此我将我的目录命名为 flags,并将三个 PNG 放入该目录中。

在一个名为 `flags.scss` 的新 SCSS 文件中(此处的名称并不重要),以下三行将按顺序导入 Compass 的雪碧图制作工具,全局导入要转换为雪碧图的 PNG(请注意,此处的路径不包含 images/),然后生成雪碧图的 CSS。请注意,**@include 语句的中间词需要与前一行的目录匹配**。

@import "compass/utilities/sprites";
@import "flags/*.png";
@include all-flags-sprites;

这是一个相当简单的生成雪碧图的过程,但它有一些缺点/怪异之处

  • 生成的 CSS 不包含雪碧图的宽度或高度。
  • 雪碧图之间没有共享类;背景图像应用于每个类。

使用 ImageMagick 生成雪碧图

ImageMagick 可用于使用以下命令从命令行创建雪碧图

convert *.png -append sprites.png # append vertically
convert *.png +append sprites.png # append horizontally

这将获取 glob 选择的所有 PNG 文件并将它们连接到单个文件中,但不会创建相应的样式表。如果您使用 ImageMagick 创建雪碧图,您可能需要阅读下面有关使用 Sprite Cow 的部分。

将 Sprite Cow 与您的雪碧图一起使用

Sprite Cow 是一种托管工具,用于生成与您的雪碧图相对应的样式表。它不会为您创建雪碧图,它只是帮助您获得使用雪碧图所需的数字(雪碧图各个部分的宽度、高度和背景位置)。它拥有 2 倍图像兼容性和一个简单的界面,可以快速指定雪碧图的哪些区域构成每个图像以创建 CSS。您只需点击所需的部件,它就会为您提供所需的 CSS。

使用 Spritepad 生成雪碧图

Spritepad 是另一个用于创建雪碧图的托管解决方案。使用 Spritepad,您可以上传单个图像,根据需要定位它们,并且 CSS 会实时更新。完成后,下载图像并将 CSS 复制到您的项目中。

使用 SpriteMe 生成雪碧图

SpriteMe 是一种书签工具,可以根据它在当前页面上找到的内容生成雪碧图。因此,从本质上讲,您根本不需要使用雪碧图来开发,然后使用它在最后将内容组合成雪碧图。这是一个工作流程,解释了它是如何工作的。

我的精灵图应该横向还是纵向?

一种选择是都不用。将它们压缩成一个网格,使其尺寸尽可能小。图像的尺寸大小会影响图像使用时占用的内存量,因此越小越好。如果你最终自己布局精灵图,Sprite Cow 是一个有助于 CSS 生成部分的不错工具。

如果为了简单起见,你打算选择其中一个,那么一种方法是查看图像文件的最大宽度和最大高度。如果最大宽度大于最大高度,则精灵图应水平排列。如果最大高度大于最大宽度,则垂直排列。如果你使用的是生成工具,它们通常会为你做出这个选择。

在某些情况下,实际上可能有意义对角线布局精灵图。这使得可以在未知宽度和高度的区域使用精灵图成为可能,这非常酷。

尽管另一种解决方法是使用伪元素

替代方案

CSS 精灵图有一些替代方案,但正如你所料,它们各自都有自己的优缺点。

数据 URI

数据 URI 允许你将图像数据直接嵌入到样式表中。这避免了对图像的额外 HTTP 请求,使其本质上与精灵图相同,但没有花哨的定位。

图标字体

图标字体类似于精灵图,因为它们实现了相同的功能:将多个图像组合到一个请求中。

SVG

SVG 图像也可以组合成精灵图并用作图标系统。不过这是一种略微不同的方法,利用了 SVG 的语法和优势。你可能需要考虑一个回退系统,因为 SVG 的浏览器支持不如 CSS background-image(CSS background-image 基本上没有任何浏览器支持问题)。

GrunticonIconizr 是用于处理 SVG 精灵图的可能性,它们有助于回退。

使用 <img> 和 object-position

Robin Rendle 有一篇关于这种巧妙技巧的精彩文章这里

示例

  • Mozilla 开发者网络 使用精灵图在切换其顶级导航时在不同状态之间切换。
  • Mailchimp 在其侧边栏导航的不同状态中使用精灵图(背景图像 SVG)。
  • Mapbox 使用图标字体在其整个站点中使用的较小图标,但使用相当高分辨率的精灵图用于社交媒体和新闻徽标。

进一步阅读