{T}

图标系统实战

携手开启这个充满创意和挑战的旅程吧!一同探索 SVG 图标设计的奥秘,为我们的项目带来新的活力和灵感!

图标系统的作用和组成部分

在当今的数字时代,图标已经成为现代 Web 应用和网站中不可或缺的一部分,同时也是设计系统中不可或缺的组成部分。你可能会好奇,为什么要创建图标系统呢?我们从以下几个方面来回答这个问题:

  • 可视化沟通和用户体验提升:图标是一种视觉语言,能够以简洁明了的方式传达信息和功能,提升用户体验。在 Web 应用和网站中,通过图标可以快速地引导用户完成操作,减少学习成本和用户犹豫的时间。一个统一且易于理解的图标系统能够提高用户的操作效率和满意度。
  • 品牌一致性和视觉识别:图标是品牌形象的重要组成部分,能够传达品牌的价值观和特色。通过统一的图标设计风格和视觉风格,可以增强品牌的一致性和识别度,让用户更容易地与品牌产生情感联系,并建立信任和忠诚度。
  • 设计系统的完整性和可维护性:图标系统是设计系统的重要组成部分,与色彩、字体元素一样,为设计提供了一致性和标准化的基础。一个完善的图标系统能够使 Web 设计师更加高效地工作,减少重复设计和修改的时间,提高设计的质量和一致性。同时,通过建立可维护的图标库和设计规范,可以实现图标的持续更新和优化,以适应 不断变化的设计需求和用户反馈。
  • 跨平台和多设备适配:在今天的多平台和多设备环境下,图标需要能够适应不同分辨率、屏幕尺寸和操作系统的要求。一个灵活且可扩展的图标系统能够提供多种格式和尺寸的图标资源,以满足各种设备和平台的需求,保证在不同环境下都能够呈现出最佳的视觉效果和用户体验。

因此,创建一个图标系统不仅能够提升用户体验、增强品牌形象,还能够提高设计效率和一致性,为设计团队和开发团队带来诸多好处。通过统一管理和维护图标资源,可以实现设计和开发的无缝协作,为用户提供更加流畅和愉悦的在线体验。

一个完善的图标系统不仅仅是一组图标的简单集合,而是由多个关键部分组成的复杂系统。其中,设计规范、图标制作工作、图标库、字体生成器、图标导出和管理系统、以及图标集成和使用指南等几个关键组成部分相辅相成,共同确保图标在设计、管理和应用过程中保持一致性、易用性和高效性。

  • 设计规范:设计规范是图标系统的基石,为图标的创作提供了准则、原则和规范。这些规范详细阐述了图标的设计风格、尺寸、颜色、比例和行为等方面,旨在确保图标在外观、可用性和识别性上的一致性。同时,设计规范也致力于与品牌形象和用户体验原则保持一致。遵循设计规范,设计团队能够更高效地创建新的图标,并确保它们与已有图标保持一致,为产品提供统一的视觉体验和用户感知。
  • 流程: 一个完善的图标系统还需要建立一个简单、高效的流程,用于管理和更新图标库。这个流程通常包括图标的提交、审查、版本控制和部署等环节。通过这个流程,团队成员可以轻松地提交新的图标,并确保它们符合设计指南和品牌标识。同时,流程还可以结合自动化工具和人工审核,以确保图标的质量和一致性。这样做可以提高团队的协作效率,减少冗余工作,从而加快产品的开发和更新速度。
  • 图标制作工具:图标制作工具是用于设计、编辑和导出图标的软件或在线平台。这些工具通常包括矢量图形编辑软件(如 Adobe Illustrator、Sketch 和 Figma 等)、图标设计工具(如 IconjarIconfinder 等)以及在线图标编辑器(如 IcoMoonFontello等)。设计师可以使用这些工具创建新的图标,或编辑现有的图标以满足特定的设计需求
  • 图标库: 图标库是图标系统的基础,其中包含了所有的图标资源。这些图标可能包括各种功能性图标、状态图标、品牌图标等,用于在应用程序、网站或其他数字平台中传达信息、引导用户操作等。图标库通常以集合或分类的形式组织,以便设计师和开发人员能够快速找到所需的图标。
  • 字体生成器: 尽管 SVG 格式的图标越来越流行,但图标字体仍然是设计过程中的重要工具。图标字体生成器是一个自动化工具,用于将一组 SVG 图标转换为字体文件,如 TTF(TrueType Font) 或 WOFF (Web Open Font Format)。通过字体生成器,设计团队可以轻松地创建和维护图标字体,无需手动构建每个图标的字体文件。这样做的好处是,设计师可以通过简单地引用字体文件中的图标来使用它们,而无需处理 SVG 文件或图标的构建和维护工作。这种方法还可以减少页面加载时间,提高网站的性能。
  • 集成到 Web 应用: 最后,一个图标系统还需要提供简单、灵活的方式,将图标集成到 Web 应用中。这可以通过将图标字体嵌入到网站的 CSS 样式表中,或者使用 SVG 图标直接嵌入到 HTML 页面中来实现。通过提供清晰的文档和示例代码,设计团队可以确保开发人员能够轻松地使用图标,并在 Web 应用中实现所需的功能和效果。这样做可以确保图标系统在实际应用中发挥最大的作用,为用户提供一致、美观的界面体验。

正如你所见,一个完善的图标系统包括设计规范、图标制作工具、流程、图标库、字体生成器以及集成到 Web 应用中等组成部分。它们共同为设计团队和开发团队提供了一致、高效、易用的图标资源和使用方式,从而促进了设计和开发工作的协作和创造。然而,在本课程中,将聚焦于图标的设计和获取,特别是探讨如何将图标系统无缝集成到 Web 应用中。

为什么是 SVG 图标?

假设你正在或需要构建一个图标系统。这个系统必须具备非规定性、可扩展性,并且能够通过 CSS 或 JavaScript 进行动态编辑。这些图标将被多个团队在许多不同的 Web 应用程序或网站中使用,而且这些应用程序和网站可能使用不同的框架和技术构建。在应用图标时,它们需要具有可重新样式化、可缓存,并且在添加更多图标时能够快速、轻松地进行更新。用一句话来概括,“图标系统需要极度灵活”。

在处理图标系统时,基本上我们有三个选择:字体图标(Icon Fonts)、CSS 数据 URI(Data URI)和 SVG 图标。讨论最多的还是字体图标和 SVG 图标。SVG成为优秀的图标系统的原因很多:

  • 可缩放性: SVG 图标是基于矢量的,可以在不损失清晰度的情况下缩放到任意大小,适应不同分辨率和屏幕尺寸。
  • 分辨率无关性: 与位图图像(如 PNG 或 JPEG )不同,SVG 图标不依赖于像素网格,因此无论在高分辨率还是低分辨率设备上都能保持清晰度。
  • 小文件大小: SVG 文件通常比等效的位图文件小得多,因为它们是基于文本的,可以通过代码压缩轻松减小文件大小。
  • 可编辑性: SVG 图标是文本文件,可以直接编辑,轻松修改颜色、形状、大小和其他属性,而不会损失质量。
  • 动态性: SVG 图标可以与 CSS 和 JavaScript 结合使用,实现各种动画效果、交互式特性和状态变化,使用户体验更加丰富和生动。
  • 可被搜索和索引: 由于 SVG 图标是文本文件,因此可以轻松地被搜索引擎索引,提高网站的可访问性和搜索引擎优化(SEO)。
  • 跨平台兼容性: SVG 是一种开放的标准,几乎所有现代浏览器都支持 SVG 格式,因此可以在各种设备和平台上无缝显示。

SVG 图标具有灵活性、清晰度、小文件大小、可编辑性、动态性、可搜索性和跨平台兼容性等诸多优势,使其成为现代 Web 设计中的理想选择。

一旦你选择了使用 SVG 图标而非字体图标,就需要思考如何优化图标的交付,以及加速图标的创建和使用速度。可以利用 SVG 雪碧图技术来做到这一点。稍后我们会与大家一起探讨创建 SVG 雪碧图的多种方式(至少三种)。尽管它们在外观或工作方式上略有不同,但其基本概念几乎相同。

准备你的图标

现如今,获得 SVG 图标有多种途径,首先从设计师团队获得,其次从第三方面图标库获得。如果你想自己从头开始设计图标,这并不是件易事。你需要制定一些规则和流程,它会可能也会因团队不同,略有差异。

以阿里妈妈的 Iconfont 为例。首先,你需要有一个统一的模板,比如图标在绘制时均以标准图标大小 1024 x 1024 绘制,因为在制作图标时需要设置较高的清晰度,所以图标路径也需要等比例放大。其次,你可以直接将画好的图标路径复制到模板里,根据模板的辅助线,对图标进行位置的调节,居中,四周等距,保证图标的统一性。

在绘制图标时,还需要要注意一些细则:

完成图标设计后,你可以从设计工具中导出 SVG 文件。然而,需要注意的是,不同的设计工具可能会导致 SVG 文件存在一些多余的标记和元素数据。有时候,路径数据可能会过于精确,导致 SVG 文件体积过大。为了优化 SVG 代码,建议使用诸如 SVGOMG 等工具进行处理。

如果你不是一名专业的 Web 设计师(仅是一名专业的 Web 开发者),要亲手设计 SVG 图标着实困难,那么你可以考虑通过第三方图标库(例如 FontAwesomeFlowbiteIconScoutFlatIconIcons8LineIconsIconFinercss.ggIconfont 等)获取相关 SVG 图标。我通常在 IconfontFontAwesome 平台上获取图标。

为了便于后续能更好的向大家演示,我从 FontAwesome 平台上下载了一些 SVG 图标,并且统一放在名为 icons 文件夹中:

注意,在 icons 中的每个 SVG 图标都是一个独立的 .svg 文件。

一旦准备好 SVG 图标文件并将它们放置在一个文件夹中(如 icons),你就拥有了自己的图标库。随后,你可以根据需要不断向 icons 文件夹中添加新的 SVG 图标。接下来,将重点讨论如何将现有的SVG图标应用于Web应用或网站。

先决条件:SVG 基础知识

接下来的内容会涉及 SVG 编码的实践阶段,你需要了解一些 SVG 基础知识,并能够阅读和理解简单 SVG 文件的结构。理想情况下,你应该了解以下内容:

  • SVG 基础知识:使用 SVG
  • SVG 基本图形元素:<line><rect><circle><ellipse><polyline><polygon><path>
  • 组织 SVG,SVG 元素分组和引用:<g><symbol><defs><use>
  • SVG 嵌入技术:SVG 嵌入 HTML 文档,CSS 中引用 SVG
  • 样式化 SVG:fillstrokesroke-width
  • SVG 片段标识符
  • SVG 坐标系统:viewBox 和 preserveAspectRatio

有了这些先决条件,开始学习如何创建 SVG 雪碧图,即将 SVG 图标应用到 Web 应用或网站!

制作 SVG 雪碧图

由于 SVG 是 XML 代码,它可以以内联方式嵌入到 HTML 文档中,作为一个代码。嵌入的 <svg> 元素将作为所有图标的容器,并将成为我们要使用的 SVG 雪碧图。

HTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SVG Sprites</title>
</head>
<body>
    <svg class="sr-only">
        <!-- SVG 图标放在这里 -->
    </svg>    
</body>
</html>

接下来,在 <svg> 元素中为每个图创建一个 <symbol> 元素,每个 <symbol> 必须有一个 id 名,这外名称最好与 icons 文件夹中的 .svg 文件同名,例如 id="twitter 对应着 icons 文件夹中的 twitter.svg

XML
<svg class="sr-only">
    <!-- Twitter -->
    <symbol id="twitter">
        <!-- 绘制 Twitter 图标的内容放在这里 -->
    </symbol>
</svg> 

使用文本编辑器,打开 icons 文件夹中的 twitter.svg 文件,其对应的 SVG 代码如下:

XML
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
    <!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
    <path d="M459.4 151.7c.3 4.5 .3 9.1 .3 13.6 0 138.7-105.6 298.6-298.6 298.6-59.5 0-114.7-17.2-161.1-47.1 8.4 1 16.6 1.3 25.3 1.3 49.1 0 94.2-16.6 130.3-44.8-46.1-1-84.8-31.2-98.1-72.8 6.5 1 13 1.6 19.8 1.6 9.4 0 18.8-1.3 27.6-3.6-48.1-9.7-84.1-52-84.1-103v-1.3c14 7.8 30.2 12.7 47.4 13.3-28.3-18.8-46.8-51-46.8-87.4 0-19.5 5.2-37.4 14.3-53 51.7 63.7 129.3 105.3 216.4 109.8-1.6-7.8-2.6-15.9-2.6-24 0-57.8 46.8-104.9 104.9-104.9 30.2 0 57.5 12.7 76.7 33.1 23.7-4.5 46.5-13.3 66.6-25.3-7.8 24.4-24.4 44.8-46.1 57.8 21.1-2.3 41.6-8.1 60.4-16.2-14.3 20.8-32.2 39.3-52.6 54.3z"/>
</svg>

我们只需要将绘制“Twitter”图标形状的部分(上面代码中的 <path> )嵌入到 id 名为 twiiter<symbol> 元素中:

XML
<svg class="sr-only">
    <!-- Twitter -->
    <symbol id="twitter">
        <path d="M459.4 151.7c.3 4.5 .3 9.1 .3 13.6 0 138.7-105.6 298.6-298.6 298.6-59.5 0-114.7-17.2-161.1-47.1 8.4 1 16.6 1.3 25.3 1.3 49.1 0 94.2-16.6 130.3-44.8-46.1-1-84.8-31.2-98.1-72.8 6.5 1 13 1.6 19.8 1.6 9.4 0 18.8-1.3 27.6-3.6-48.1-9.7-84.1-52-84.1-103v-1.3c14 7.8 30.2 12.7 47.4 13.3-28.3-18.8-46.8-51-46.8-87.4 0-19.5 5.2-37.4 14.3-53 51.7 63.7 129.3 105.3 216.4 109.8-1.6-7.8-2.6-15.9-2.6-24 0-57.8 46.8-104.9 104.9-104.9 30.2 0 57.5 12.7 76.7 33.1 23.7-4.5 46.5-13.3 66.6-25.3-7.8 24.4-24.4 44.8-46.1 57.8 21.1-2.3 41.6-8.1 60.4-16.2-14.3 20.8-32.2 39.3-52.6 54.3z" />
    </symbol>
</svg> 

<symbol> 可以有自己的 viewBox 属性,这使得在任何时候都可以控制它的内容在其容器内的位置。因此,使用 <symbol> 元素实例化 icons 中每个 SVG 图标时,应该将相应图标的 viewBox 属性值复制给 <symbol> 元素。例如,上面示例中的“Twitter”图标(twitter.svg),它的 <svg> 元素的 viewBox 的值为 0 0 520 520 ,因此,我们应该将该值赋予给 <symbol> 元素的 viewBox 属性:

XML
<svg class="sr-only">
    <!-- Twitter -->
    <symbol id="twitter" viewBox="0 0 512 512">
        <path d="M459.4 151.7c.3 4.5 .3 9.1 .3 13.6 0 138.7-105.6 298.6-298.6 298.6-59.5 0-114.7-17.2-161.1-47.1 8.4 1 16.6 1.3 25.3 1.3 49.1 0 94.2-16.6 130.3-44.8-46.1-1-84.8-31.2-98.1-72.8 6.5 1 13 1.6 19.8 1.6 9.4 0 18.8-1.3 27.6-3.6-48.1-9.7-84.1-52-84.1-103v-1.3c14 7.8 30.2 12.7 47.4 13.3-28.3-18.8-46.8-51-46.8-87.4 0-19.5 5.2-37.4 14.3-53 51.7 63.7 129.3 105.3 216.4 109.8-1.6-7.8-2.6-15.9-2.6-24 0-57.8 46.8-104.9 104.9-104.9 30.2 0 57.5 12.7 76.7 33.1 23.7-4.5 46.5-13.3 66.6-25.3-7.8 24.4-24.4 44.8-46.1 57.8 21.1-2.3 41.6-8.1 60.4-16.2-14.3 20.8-32.2 39.3-52.6 54.3z" />
    </symbol>
</svg> 

如果你的图标库中的所有 SVG 图标都是按同一标准和尺寸设计的,你可以忽略 <symbol> 元素上的 viewBox 属性的设置。要是你图标库中的 SVG 图标并没有遵循统一标准设计,而是从不同平台上获取的 SVG 图标,那么每个图标的尺寸就会有所差异。例如, FontAwesome 平台上的图标的 <svg> 元素的 viewBox 属性值普遍都是 0 0 512 512 ,而 iconfont 平台上的图标的 <svg> 元素的 viewBox 属性值普遍都是 0 0 1024 1024

XML
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1711789057624" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4354" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
    <path d="M350.65 447.74c7.22-13.06 21.02-21.18 35.97-21.18l1.75 0.04c15.13 0.5 28.87 9.53 35.49 23.55l40 84.85 61.48-156.37c6.17-15.76 21.11-26 38.06-26.1 17.04 0 32 10.06 38.35 25.61l40.96 100.61 20.43-20.83c8.12-8.25 18.99-12.49 30.41-12.32 11.27 0.25 22.12 5.26 29.67 13.72l47.05 52.64h33.44c9.26-13.67 17.61-27.82 24.51-42.4 30.42-64.23 23.59-130.04-22.05-186.44-41.53-51.33-121.95-71.79-187.05-45.57-38.15 15.37-71.97 41.49-112.01 65.31-2.23-1.97-7.78-7.31-13.78-12.1-31.19-24.89-62.45-50.17-102.81-58.46-91.81-18.88-202.64 20.66-210.51 151.13-2.68 44.39 8.82 83.01 29.19 117.41h111.92l29.53-53.1z" p-id="4355"></path>
    <path d="M691.82 517.5l-27.12 27.65c-9.74 9.92-23.68 14.23-37.33 11.57-13.68-2.69-24.96-11.99-30.19-24.89l-33.2-81.55-60.08 152.79a41.117 41.117 0 0 1-36.97 26.08l-1.37 0.03c-16.08 0-30.34-9.06-37.2-23.63l-43.27-91.79-15.61 28.09a41.164 41.164 0 0 1-35.97 21.18h-74.56c74.41 74.49 151.59 146.23 227.63 219.09 21.93 21.02 29.11 21.07 51.4-0.32 71.87-68.95 145.17-136.51 214.65-207.78 0.22-0.22 0.43-0.45 0.64-0.67-8.83-1.67-16.99-6.11-23.08-12.9l-38.37-42.95z" p-id="4356"></path>
    <path d="M465.11 607.07c-7.45 0-13.99-4.14-17.19-10.93l-60.77-128.89c-0.08-0.18-0.28-0.6-0.94-0.62-0.58 0.09-0.88 0.39-0.98 0.56l-35.51 63.93c-3.36 6.04-9.74 9.8-16.65 9.8H186.22c-4.96 0-8.99-4.02-8.99-8.99 0-4.96 4.02-8.99 8.99-8.99h146.84c0.39 0 0.75-0.21 0.94-0.55l35.51-63.93c3.38-6.09 9.72-9.8 16.64-9.8 0.22 0 0.44 0 0.65 0.01 7.18 0.24 13.54 4.42 16.6 10.92l60.76 128.89c0.09 0.21 0.31 0.56 1.01 0.62 0.71-0.02 0.89-0.47 0.97-0.68l79.31-201.7c2.86-7.29 9.78-12.03 17.61-12.08h0.12c7.79 0 14.7 4.65 17.64 11.87l53.03 130.24c0.05 0.13 0.22 0.54 0.79 0.65 0.56 0.11 0.87-0.2 0.98-0.3l42.85-43.69c3.68-3.75 8.65-5.84 14.05-5.7 5.24 0.12 10.26 2.44 13.76 6.35l53.34 59.67c0.28 0.13 0.53 0.23 0.81 0.36h65.59c4.96 0 8.99 4.02 8.99 8.99 0 4.96-4.02 8.99-8.99 8.99h-65.59c-5.42 0-10.59-2.31-14.2-6.35l-53.34-59.68c-0.2-0.23-0.47-0.35-0.78-0.36-0.16 0.06-0.58 0.1-0.8 0.32l-42.84 43.69c-4.51 4.59-10.95 6.6-17.28 5.35a19.009 19.009 0 0 1-13.96-11.51L564.2 393.29c-0.09-0.24-0.35-0.69-1.01-0.67-0.73 0-0.9 0.45-0.99 0.68L482.89 595c-2.83 7.19-9.38 11.81-17.1 12.07h-0.68z" p-id="4357"></path>
</svg>

这种情形之下,如果不在 <symbol> 元素上定义 viewBox 属性,那么在页面的其他位置使用 SVG 的 <use> 元素引用 <symbol> 需要指 viewBox ,否则 SVG 图标不会如你预期的那样呈现:

XML
<!-- 未显式设置 viewBox -->
<svg  class="icon" >
    <use href="#twitter" />
</svg>
 
<svg class="icon" >
    <use href="#heart" />
</svg>
 
<!-- viewBox 值来自于 twitter.svg 的 viewBox -->
<svg  class="icon" viewBox="0 0 512 512">
    <use href="#twitter" />
</svg>
 
<svg class="icon" viewBox="0 0 512 512">
    <use href="#heart" />
</svg>
 
<!-- viewBox 值来自于 heart.svg 的 viewBox -->
<svg  class="icon" viewBox="0 0 1024 1024">
    <use href="#twitter" />
</svg>
 
<svg class="icon" viewBox="0 0 1024 1024">
    <use href="#heart" />
</svg>
 
<!-- viewBox 值来自于 twitter.svg 的 viewBox -->
<svg  class="icon" viewBox="0 0 512 512">
    <use href="#twitter" />
</svg>
 
<!-- viewBox 值来自于 heart.svg 的 viewBox -->
<svg class="icon" viewBox="0 0 1024 1024">
    <use href="#heart" />
</svg>

Demo 地址:https://codepen.io/airen/full/YzMrJrB

反过来则截然不同:

Demo 地址:https://codepen.io/airen/full/MWREPrm

这也是我为什么强调,在使用 <symbol> 实例化 SVG 图标时,应该显式设置 viewBox 属性的值,并且要与对应 .svg 文件的根元素的 <svg> 元素的 viewBox 属性值保持一致。

如果手工创建 SVG 图标,这里有一个小技巧。你可以使用诸如 SVGOMG 工具对 icons 文件夹中的 SVG 图标进行优化,只保留 viewBox 属性和必要的数据(绘制图形所需的数据)。以 heart.svg 为例,优化后的代码如下:

XML
<svg class="icon" viewBox="0 0 1024 1024">
    <path d="M350.65 447.74c7.22-13.06 21.02-21.18 35.97-21.18l1.75.04c15.13.5 28.87 9.53 35.49 23.55l40 84.85 61.48-156.37c6.17-15.76 21.11-26 38.06-26.1 17.04 0 32 10.06 38.35 25.61l40.96 100.61 20.43-20.83c8.12-8.25 18.99-12.49 30.41-12.32 11.27.25 22.12 5.26 29.67 13.72l47.05 52.64h33.44c9.26-13.67 17.61-27.82 24.51-42.4 30.42-64.23 23.59-130.04-22.05-186.44-41.53-51.33-121.95-71.79-187.05-45.57-38.15 15.37-71.97 41.49-112.01 65.31-2.23-1.97-7.78-7.31-13.78-12.1-31.19-24.89-62.45-50.17-102.81-58.46-91.81-18.88-202.64 20.66-210.51 151.13-2.68 44.39 8.82 83.01 29.19 117.41h111.92l29.53-53.1z"/>
    <path d="m691.82 517.5-27.12 27.65c-9.74 9.92-23.68 14.23-37.33 11.57-13.68-2.69-24.96-11.99-30.19-24.89l-33.2-81.55-60.08 152.79a41.117 41.117 0 0 1-36.97 26.08l-1.37.03c-16.08 0-30.34-9.06-37.2-23.63l-43.27-91.79-15.61 28.09a41.164 41.164 0 0 1-35.97 21.18h-74.56c74.41 74.49 151.59 146.23 227.63 219.09 21.93 21.02 29.11 21.07 51.4-.32 71.87-68.95 145.17-136.51 214.65-207.78.22-.22.43-.45.64-.67-8.83-1.67-16.99-6.11-23.08-12.9l-38.37-42.95z"/>
    <path d="M465.11 607.07c-7.45 0-13.99-4.14-17.19-10.93l-60.77-128.89c-.08-.18-.28-.6-.94-.62-.58.09-.88.39-.98.56l-35.51 63.93c-3.36 6.04-9.74 9.8-16.65 9.8H186.22c-4.96 0-8.99-4.02-8.99-8.99 0-4.96 4.02-8.99 8.99-8.99h146.84c.39 0 .75-.21.94-.55l35.51-63.93c3.38-6.09 9.72-9.8 16.64-9.8.22 0 .44 0 .65.01 7.18.24 13.54 4.42 16.6 10.92l60.76 128.89c.09.21.31.56 1.01.62.71-.02.89-.47.97-.68l79.31-201.7c2.86-7.29 9.78-12.03 17.61-12.08h.12c7.79 0 14.7 4.65 17.64 11.87l53.03 130.24c.05.13.22.54.79.65.56.11.87-.2.98-.3l42.85-43.69c3.68-3.75 8.65-5.84 14.05-5.7 5.24.12 10.26 2.44 13.76 6.35l53.34 59.67c.28.13.53.23.81.36h65.59c4.96 0 8.99 4.02 8.99 8.99 0 4.96-4.02 8.99-8.99 8.99h-65.59c-5.42 0-10.59-2.31-14.2-6.35l-53.34-59.68c-.2-.23-.47-.35-.78-.36-.16.06-.58.1-.8.32l-42.84 43.69c-4.51 4.59-10.95 6.6-17.28 5.35a19.009 19.009 0 0 1-13.96-11.51L564.2 393.29c-.09-.24-.35-.69-1.01-.67-.73 0-.9.45-.99.68L482.89 595c-2.83 7.19-9.38 11.81-17.1 12.07h-.68z"/>
</svg>

你可以直接将优化后的代码嵌套到 svg.sr-only 中,并把 <svg> 元素替换成 <symbol> ,同时把 class 换成与文件同名的 id

XML
<svg class="sr-only">
    <!-- Twitter -->
    <symbol id="twitter" viewBox="0 0 512 512">
        <path d="M459.4 151.7c.3 4.5 .3 9.1 .3 13.6 0 138.7-105.6 298.6-298.6 298.6-59.5 0-114.7-17.2-161.1-47.1 8.4 1 16.6 1.3 25.3 1.3 49.1 0 94.2-16.6 130.3-44.8-46.1-1-84.8-31.2-98.1-72.8 6.5 1 13 1.6 19.8 1.6 9.4 0 18.8-1.3 27.6-3.6-48.1-9.7-84.1-52-84.1-103v-1.3c14 7.8 30.2 12.7 47.4 13.3-28.3-18.8-46.8-51-46.8-87.4 0-19.5 5.2-37.4 14.3-53 51.7 63.7 129.3 105.3 216.4 109.8-1.6-7.8-2.6-15.9-2.6-24 0-57.8 46.8-104.9 104.9-104.9 30.2 0 57.5 12.7 76.7 33.1 23.7-4.5 46.5-13.3 66.6-25.3-7.8 24.4-24.4 44.8-46.1 57.8 21.1-2.3 41.6-8.1 60.4-16.2-14.3 20.8-32.2 39.3-52.6 54.3z" />
    </symbol>
 
    <!-- Heart -->
    <symbol id="heart" viewBox="0 0 1024 1024">
        <path d="M350.65 447.74c7.22-13.06 21.02-21.18 35.97-21.18l1.75.04c15.13.5 28.87 9.53 35.49 23.55l40 84.85 61.48-156.37c6.17-15.76 21.11-26 38.06-26.1 17.04 0 32 10.06 38.35 25.61l40.96 100.61 20.43-20.83c8.12-8.25 18.99-12.49 30.41-12.32 11.27.25 22.12 5.26 29.67 13.72l47.05 52.64h33.44c9.26-13.67 17.61-27.82 24.51-42.4 30.42-64.23 23.59-130.04-22.05-186.44-41.53-51.33-121.95-71.79-187.05-45.57-38.15 15.37-71.97 41.49-112.01 65.31-2.23-1.97-7.78-7.31-13.78-12.1-31.19-24.89-62.45-50.17-102.81-58.46-91.81-18.88-202.64 20.66-210.51 151.13-2.68 44.39 8.82 83.01 29.19 117.41h111.92l29.53-53.1z"/>
        <path d="m691.82 517.5-27.12 27.65c-9.74 9.92-23.68 14.23-37.33 11.57-13.68-2.69-24.96-11.99-30.19-24.89l-33.2-81.55-60.08 152.79a41.117 41.117 0 0 1-36.97 26.08l-1.37.03c-16.08 0-30.34-9.06-37.2-23.63l-43.27-91.79-15.61 28.09a41.164 41.164 0 0 1-35.97 21.18h-74.56c74.41 74.49 151.59 146.23 227.63 219.09 21.93 21.02 29.11 21.07 51.4-.32 71.87-68.95 145.17-136.51 214.65-207.78.22-.22.43-.45.64-.67-8.83-1.67-16.99-6.11-23.08-12.9l-38.37-42.95z"/>
        <path d="M465.11 607.07c-7.45 0-13.99-4.14-17.19-10.93l-60.77-128.89c-.08-.18-.28-.6-.94-.62-.58.09-.88.39-.98.56l-35.51 63.93c-3.36 6.04-9.74 9.8-16.65 9.8H186.22c-4.96 0-8.99-4.02-8.99-8.99 0-4.96 4.02-8.99 8.99-8.99h146.84c.39 0 .75-.21.94-.55l35.51-63.93c3.38-6.09 9.72-9.8 16.64-9.8.22 0 .44 0 .65.01 7.18.24 13.54 4.42 16.6 10.92l60.76 128.89c.09.21.31.56 1.01.62.71-.02.89-.47.97-.68l79.31-201.7c2.86-7.29 9.78-12.03 17.61-12.08h.12c7.79 0 14.7 4.65 17.64 11.87l53.03 130.24c.05.13.22.54.79.65.56.11.87-.2.98-.3l42.85-43.69c3.68-3.75 8.65-5.84 14.05-5.7 5.24.12 10.26 2.44 13.76 6.35l53.34 59.67c.28.13.53.23.81.36h65.59c4.96 0 8.99 4.02 8.99 8.99 0 4.96-4.02 8.99-8.99 8.99h-65.59c-5.42 0-10.59-2.31-14.2-6.35l-53.34-59.68c-.2-.23-.47-.35-.78-.36-.16.06-.58.1-.8.32l-42.84 43.69c-4.51 4.59-10.95 6.6-17.28 5.35a19.009 19.009 0 0 1-13.96-11.51L564.2 393.29c-.09-.24-.35-.69-1.01-.67-.73 0-.9.45-.99.68L482.89 595c-2.83 7.19-9.38 11.81-17.1 12.07h-.68z"/>
    </symbol>
</svg>

其他图标重复以上步骤。

HTML
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>SVG Sprites</title>
    </head>
    <body>
        <svg class="sr-only">
            <symbol viewBox="0 0 448 512" id="dribbble">
                <path d="M165.9 132.5c-38.3 18-66.8 53.3-75.7 95.7c6.1 .1 62.4 .3 126.4-16.7c-22.7-40.2-47.1-74.1-50.7-79zm26.1-9.1c3.8 5.1 28.6 38.9 51 80c48.6-18.3 69.1-45.9 71.6-49.4C281 124.2 235.3 112.9 192 123.4zM277.4 382c-2-12-10-53.8-29.2-103.6c-55.1 18.8-93.8 56.4-108.1 85.6c40.5 31.6 93.3 36.7 137.3 18zM227.8 232.6C159.6 253 93.4 252.2 87.4 252c0 .7 0 1.4 0 2.1s0 1.4 0 2.1c0 35.1 13.3 67.1 35.1 91.4c22.2-37.9 67.1-77.9 116.5-91.8c-3.4-7.8-7.2-15.5-11.1-23.2zm72.5 136.9c30.7-20.7 52.5-53.6 58.6-91.6c-4.6-1.5-42.3-12.7-85.1-5.8c17.9 49.1 25.1 89.1 26.5 97.4zm-34.8-119c45.5-5.7 90.7 3.4 95.2 4.4c-.3-32.3-11.8-61.9-30.9-85.1c-2.9 3.9-25.8 33.2-76.3 53.9c4.8 9.8 8.3 17.8 12 26.8zM384 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64zM224 416a160 160 0 1 1 0-320 160 160 0 1 1 0 320z" />
            </symbol>
            <symbol viewBox="0 0 448 512" id="facebook">
                <path d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64h98.2V334.2H109.4V256h52.8V222.3c0-87.1 39.4-127.5 125-127.5c16.2 0 44.2 3.2 55.7 6.4V172c-6-.6-16.5-1-29.6-1c-42 0-58.2 15.9-58.2 57.2V256h83.6l-14.4 78.2H255V480H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64z" />
            </symbol>
            <symbol viewBox="0 0 448 512" id="github">
                <path d="M448 96c0-35.3-28.7-64-64-64H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96zM265.8 407.7c0-1.8 0-6 .1-11.6c.1-11.4 .1-28.8 .1-43.7c0-15.6-5.2-25.5-11.3-30.7c37-4.1 76-9.2 76-73.1c0-18.2-6.5-27.3-17.1-39c1.7-4.3 7.4-22-1.7-45c-13.9-4.3-45.7 17.9-45.7 17.9c-13.2-3.7-27.5-5.6-41.6-5.6s-28.4 1.9-41.6 5.6c0 0-31.8-22.2-45.7-17.9c-9.1 22.9-3.5 40.6-1.7 45c-10.6 11.7-15.6 20.8-15.6 39c0 63.6 37.3 69 74.3 73.1c-4.8 4.3-9.1 11.7-10.6 22.3c-9.5 4.3-33.8 11.7-48.3-13.9c-9.1-15.8-25.5-17.1-25.5-17.1c-16.2-.2-1.1 10.2-1.1 10.2c10.8 5 18.4 24.2 18.4 24.2c9.7 29.7 56.1 19.7 56.1 19.7c0 9 .1 21.7 .1 30.6c0 4.8 .1 8.6 .1 10c0 4.3-3 9.5-11.5 8C106 393.6 59.8 330.8 59.8 257.4c0-91.8 70.2-161.5 162-161.5s166.2 69.7 166.2 161.5c.1 73.4-44.7 136.3-110.7 158.3c-8.4 1.5-11.5-3.7-11.5-8zm-90.5-54.8c-.2-1.5 1.1-2.8 3-3.2c1.9-.2 3.7 .6 3.9 1.9c.3 1.3-1 2.6-3 3c-1.9 .4-3.7-.4-3.9-1.7zm-9.1 3.2c-2.2 .2-3.7-.9-3.7-2.4c0-1.3 1.5-2.4 3.5-2.4c1.9-.2 3.7 .9 3.7 2.4c0 1.3-1.5 2.4-3.5 2.4zm-14.3-2.2c-1.9-.4-3.2-1.9-2.8-3.2s2.4-1.9 4.1-1.5c2 .6 3.3 2.1 2.8 3.4c-.4 1.3-2.4 1.9-4.1 1.3zm-12.5-7.3c-1.5-1.3-1.9-3.2-.9-4.1c.9-1.1 2.8-.9 4.3 .6c1.3 1.3 1.8 3.3 .9 4.1c-.9 1.1-2.8 .9-4.3-.6zm-8.5-10c-1.1-1.5-1.1-3.2 0-3.9c1.1-.9 2.8-.2 3.7 1.3c1.1 1.5 1.1 3.3 0 4.1c-.9 .6-2.6 0-3.7-1.5zm-6.3-8.8c-1.1-1.3-1.3-2.8-.4-3.5c.9-.9 2.4-.4 3.5 .6c1.1 1.3 1.3 2.8 .4 3.5c-.9 .9-2.4 .4-3.5-.6zm-6-6.4c-1.3-.6-1.9-1.7-1.5-2.6c.4-.6 1.5-.9 2.8-.4c1.3 .7 1.9 1.8 1.5 2.6c-.4 .9-1.7 1.1-2.8 .4z" />
            </symbol>
            <symbol viewBox="0 0 448 512" id="google-plus">
                <path d="M448 96c0-35.3-28.7-64-64-64H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96zM64 256c0-55.3 44.7-100 100-100c27 0 49.5 9.8 67 26.2l-27.1 26.1c-7.4-7.1-20.3-15.4-39.8-15.4c-34.1 0-61.9 28.2-61.9 63.2c0 34.9 27.8 63.2 61.9 63.2c39.6 0 54.4-28.5 56.8-43.1H164V241.8h94.4c1 5 1.6 10.1 1.6 16.6c0 57.1-38.3 97.6-96 97.6c-55.3 0-100-44.7-100-100zm291 18.2v29H325.8v-29h-29V245h29V216H355v29h29v29.2H355z" />
            </symbol>
            <symbol viewBox="0 0 1024 1024" id="heart">
                <path d="M350.65 447.74c7.22-13.06 21.02-21.18 35.97-21.18l1.75 0.04c15.13 0.5 28.87 9.53 35.49 23.55l40 84.85 61.48-156.37c6.17-15.76 21.11-26 38.06-26.1 17.04 0 32 10.06 38.35 25.61l40.96 100.61 20.43-20.83c8.12-8.25 18.99-12.49 30.41-12.32 11.27 0.25 22.12 5.26 29.67 13.72l47.05 52.64h33.44c9.26-13.67 17.61-27.82 24.51-42.4 30.42-64.23 23.59-130.04-22.05-186.44-41.53-51.33-121.95-71.79-187.05-45.57-38.15 15.37-71.97 41.49-112.01 65.31-2.23-1.97-7.78-7.31-13.78-12.1-31.19-24.89-62.45-50.17-102.81-58.46-91.81-18.88-202.64 20.66-210.51 151.13-2.68 44.39 8.82 83.01 29.19 117.41h111.92l29.53-53.1z" />
                <path d="M691.82 517.5l-27.12 27.65c-9.74 9.92-23.68 14.23-37.33 11.57-13.68-2.69-24.96-11.99-30.19-24.89l-33.2-81.55-60.08 152.79a41.117 41.117 0 0 1-36.97 26.08l-1.37 0.03c-16.08 0-30.34-9.06-37.2-23.63l-43.27-91.79-15.61 28.09a41.164 41.164 0 0 1-35.97 21.18h-74.56c74.41 74.49 151.59 146.23 227.63 219.09 21.93 21.02 29.11 21.07 51.4-0.32 71.87-68.95 145.17-136.51 214.65-207.78 0.22-0.22 0.43-0.45 0.64-0.67-8.83-1.67-16.99-6.11-23.08-12.9l-38.37-42.95z" />
                <path d="M465.11 607.07c-7.45 0-13.99-4.14-17.19-10.93l-60.77-128.89c-0.08-0.18-0.28-0.6-0.94-0.62-0.58 0.09-0.88 0.39-0.98 0.56l-35.51 63.93c-3.36 6.04-9.74 9.8-16.65 9.8H186.22c-4.96 0-8.99-4.02-8.99-8.99 0-4.96 4.02-8.99 8.99-8.99h146.84c0.39 0 0.75-0.21 0.94-0.55l35.51-63.93c3.38-6.09 9.72-9.8 16.64-9.8 0.22 0 0.44 0 0.65 0.01 7.18 0.24 13.54 4.42 16.6 10.92l60.76 128.89c0.09 0.21 0.31 0.56 1.01 0.62 0.71-0.02 0.89-0.47 0.97-0.68l79.31-201.7c2.86-7.29 9.78-12.03 17.61-12.08h0.12c7.79 0 14.7 4.65 17.64 11.87l53.03 130.24c0.05 0.13 0.22 0.54 0.79 0.65 0.56 0.11 0.87-0.2 0.98-0.3l42.85-43.69c3.68-3.75 8.65-5.84 14.05-5.7 5.24 0.12 10.26 2.44 13.76 6.35l53.34 59.67c0.28 0.13 0.53 0.23 0.81 0.36h65.59c4.96 0 8.99 4.02 8.99 8.99 0 4.96-4.02 8.99-8.99 8.99h-65.59c-5.42 0-10.59-2.31-14.2-6.35l-53.34-59.68c-0.2-0.23-0.47-0.35-0.78-0.36-0.16 0.06-0.58 0.1-0.8 0.32l-42.84 43.69c-4.51 4.59-10.95 6.6-17.28 5.35a19.009 19.009 0 0 1-13.96-11.51L564.2 393.29c-0.09-0.24-0.35-0.69-1.01-0.67-0.73 0-0.9 0.45-0.99 0.68L482.89 595c-2.83 7.19-9.38 11.81-17.1 12.07h-0.68z" />
            </symbol>
            <symbol viewBox="0 0 448 512" id="instagram">
                <path d="M194.4 211.7a53.3 53.3 0 1 0 59.3 88.7 53.3 53.3 0 1 0 -59.3-88.7zm142.3-68.4c-5.2-5.2-11.5-9.3-18.4-12c-18.1-7.1-57.6-6.8-83.1-6.5c-4.1 0-7.9 .1-11.2 .1c-3.3 0-7.2 0-11.4-.1c-25.5-.3-64.8-.7-82.9 6.5c-6.9 2.7-13.1 6.8-18.4 12s-9.3 11.5-12 18.4c-7.1 18.1-6.7 57.7-6.5 83.2c0 4.1 .1 7.9 .1 11.1s0 7-.1 11.1c-.2 25.5-.6 65.1 6.5 83.2c2.7 6.9 6.8 13.1 12 18.4s11.5 9.3 18.4 12c18.1 7.1 57.6 6.8 83.1 6.5c4.1 0 7.9-.1 11.2-.1c3.3 0 7.2 0 11.4 .1c25.5 .3 64.8 .7 82.9-6.5c6.9-2.7 13.1-6.8 18.4-12s9.3-11.5 12-18.4c7.2-18 6.8-57.4 6.5-83c0-4.2-.1-8.1-.1-11.4s0-7.1 .1-11.4c.3-25.5 .7-64.9-6.5-83l0 0c-2.7-6.9-6.8-13.1-12-18.4zm-67.1 44.5A82 82 0 1 1 178.4 324.2a82 82 0 1 1 91.1-136.4zm29.2-1.3c-3.1-2.1-5.6-5.1-7.1-8.6s-1.8-7.3-1.1-11.1s2.6-7.1 5.2-9.8s6.1-4.5 9.8-5.2s7.6-.4 11.1 1.1s6.5 3.9 8.6 7s3.2 6.8 3.2 10.6c0 2.5-.5 5-1.4 7.3s-2.4 4.4-4.1 6.2s-3.9 3.2-6.2 4.2s-4.8 1.5-7.3 1.5l0 0c-3.8 0-7.5-1.1-10.6-3.2zM448 96c0-35.3-28.7-64-64-64H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96zM357 389c-18.7 18.7-41.4 24.6-67 25.9c-26.4 1.5-105.6 1.5-132 0c-25.6-1.3-48.3-7.2-67-25.9s-24.6-41.4-25.8-67c-1.5-26.4-1.5-105.6 0-132c1.3-25.6 7.1-48.3 25.8-67s41.5-24.6 67-25.8c26.4-1.5 105.6-1.5 132 0c25.6 1.3 48.3 7.1 67 25.8s24.6 41.4 25.8 67c1.5 26.3 1.5 105.4 0 131.9c-1.3 25.6-7.1 48.3-25.8 67z" />
            </symbol>
            <symbol viewBox="0 0 448 512" id="linkedin">
                <path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z" />
            </symbol>
            <symbol viewBox="0 0 640 512" id="medium">
                <path d="M180.5 74.3C80.8 74.3 0 155.6 0 256S80.8 437.7 180.5 437.7 361 356.4 361 256 280.2 74.3 180.5 74.3zm288.3 10.6c-49.8 0-90.2 76.6-90.2 171.1s40.4 171.1 90.3 171.1 90.3-76.6 90.3-171.1H559C559 161.5 518.6 84.9 468.8 84.9zm139.5 17.8c-17.5 0-31.7 68.6-31.7 153.3s14.2 153.3 31.7 153.3S640 340.6 640 256C640 171.4 625.8 102.7 608.3 102.7z" />
            </symbol>
            <symbol viewBox="0 0 496 512" id="pinterest">
                <path d="M496 256c0 137-111 248-248 248-25.6 0-50.2-3.9-73.4-11.1 10.1-16.5 25.2-43.5 30.8-65 3-11.6 15.4-59 15.4-59 8.1 15.4 31.7 28.5 56.8 28.5 74.8 0 128.7-68.8 128.7-154.3 0-81.9-66.9-143.2-152.9-143.2-107 0-163.9 71.8-163.9 150.1 0 36.4 19.4 81.7 50.3 96.1 4.7 2.2 7.2 1.2 8.3-3.3 .8-3.4 5-20.3 6.9-28.1 .6-2.5 .3-4.7-1.7-7.1-10.1-12.5-18.3-35.3-18.3-56.6 0-54.7 41.4-107.6 112-107.6 60.9 0 103.6 41.5 103.6 100.9 0 67.1-33.9 113.6-78 113.6-24.3 0-42.6-20.1-36.7-44.8 7-29.5 20.5-61.3 20.5-82.6 0-19-10.2-34.9-31.4-34.9-24.9 0-44.9 25.7-44.9 60.2 0 22 7.4 36.8 7.4 36.8s-24.5 103.8-29 123.2c-5 21.4-3 51.6-.9 71.2C65.4 450.9 0 361.1 0 256 0 119 111 8 248 8s248 111 248 248z" />
            </symbol>
            <symbol viewBox="0 0 448 512" id="qq">
                <path d="M433.8 420.4c-11.5 1.4-44.9-52.7-44.9-52.7 0 31.3-16.1 72.2-51.1 101.8 16.8 5.2 54.8 19.2 45.8 34.4-7.3 12.3-125.5 7.9-159.6 4-34.1 3.8-152.3 8.3-159.6-4-9-15.3 28.9-29.2 45.8-34.4-34.9-29.5-51.1-70.4-51.1-101.8 0 0-33.3 54.1-44.9 52.7-5.4-.7-12.4-29.6 9.3-99.7 10.3-33 22-60.5 40.1-105.8C60.7 98.1 109 0 224 0c113.7 0 163.2 96.1 160.3 215 18.1 45.2 29.9 72.9 40.1 105.8 21.8 70.1 14.7 99.1 9.3 99.7z" />
            </symbol>
            <symbol viewBox="0 0 512 512" id="reddit">
                <path d="M0 256C0 114.6 114.6 0 256 0S512 114.6 512 256s-114.6 256-256 256L37.1 512c-13.7 0-20.5-16.5-10.9-26.2L75 437C28.7 390.7 0 326.7 0 256zM349.6 153.6c23.6 0 42.7-19.1 42.7-42.7s-19.1-42.7-42.7-42.7c-20.6 0-37.8 14.6-41.8 34c-34.5 3.7-61.4 33-61.4 68.4l0 .2c-37.5 1.6-71.8 12.3-99 29.1c-10.1-7.8-22.8-12.5-36.5-12.5c-33 0-59.8 26.8-59.8 59.8c0 24 14.1 44.6 34.4 54.1c2 69.4 77.6 125.2 170.6 125.2s168.7-55.9 170.6-125.3c20.2-9.6 34.1-30.2 34.1-54c0-33-26.8-59.8-59.8-59.8c-13.7 0-26.3 4.6-36.4 12.4c-27.4-17-62.1-27.7-100-29.1l0-.2c0-25.4 18.9-46.5 43.4-49.9l0 0c4.4 18.8 21.3 32.8 41.5 32.8zM177.1 246.9c16.7 0 29.5 17.6 28.5 39.3s-13.5 29.6-30.3 29.6s-31.4-8.8-30.4-30.5s15.4-38.3 32.1-38.3zm190.1 38.3c1 21.7-13.7 30.5-30.4 30.5s-29.3-7.9-30.3-29.6c-1-21.7 11.8-39.3 28.5-39.3s31.2 16.6 32.1 38.3zm-48.1 56.7c-10.3 24.6-34.6 41.9-63 41.9s-52.7-17.3-63-41.9c-1.2-2.9 .8-6.2 3.9-6.5c18.4-1.9 38.3-2.9 59.1-2.9s40.7 1 59.1 2.9c3.1 .3 5.1 3.6 3.9 6.5z" />
            </symbol>
            <symbol viewBox="0 0 496 512" id="telegram">
                <path d="M248 8C111 8 0 119 0 256S111 504 248 504 496 393 496 256 385 8 248 8zM363 176.7c-3.7 39.2-19.9 134.4-28.1 178.3-3.5 18.6-10.3 24.8-16.9 25.4-14.4 1.3-25.3-9.5-39.3-18.7-21.8-14.3-34.2-23.2-55.3-37.2-24.5-16.1-8.6-25 5.3-39.5 3.7-3.8 67.1-61.5 68.3-66.7 .2-.7 .3-3.1-1.2-4.4s-3.6-.8-5.1-.5q-3.3 .7-104.6 69.1-14.8 10.2-26.9 9.9c-8.9-.2-25.9-5-38.6-9.1-15.5-5-27.9-7.7-26.8-16.3q.8-6.7 18.5-13.7 108.4-47.2 144.6-62.3c68.9-28.6 83.2-33.6 92.5-33.8 2.1 0 6.6 .5 9.6 2.9a10.5 10.5 0 0 1 3.5 6.7A43.8 43.8 0 0 1 363 176.7z" />
            </symbol>
            <symbol viewBox="0 0 448 512" id="tiktok">
                <path d="M448 209.9a210.1 210.1 0 0 1 -122.8-39.3V349.4A162.6 162.6 0 1 1 185 188.3V278.2a74.6 74.6 0 1 0 52.2 71.2V0l88 0a121.2 121.2 0 0 0 1.9 22.2h0A122.2 122.2 0 0 0 381 102.4a121.4 121.4 0 0 0 67 20.1z" />
            </symbol>
            <symbol viewBox="0 0 448 512" id="tumblr">
                <path  d="M448 96c0-35.3-28.7-64-64-64H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96zM256.8 416c-75.5 0-91.9-55.5-91.9-87.9v-90H135.2c-3.4 0-6.2-2.8-6.2-6.2V189.4c0-4.5 2.8-8.5 7.1-10c38.8-13.7 50.9-47.5 52.7-73.2c.5-6.9 4.1-10.2 10-10.2h44.3c3.4 0 6.2 2.8 6.2 6.2v72h51.9c3.4 0 6.2 2.8 6.2 6.2v51.1c0 3.4-2.8 6.2-6.2 6.2H249.1V321c0 21.4 14.8 33.5 42.5 22.4c3-1.2 5.6-2 8-1.4c2.2 .5 3.6 2.1 4.6 4.9L318 387.1c1 3.2 2 6.7-.3 9.1c-8.5 9.1-31.2 19.8-60.9 19.8z" />
            </symbol>
            <symbol viewBox="0 0 512 512" id="twitter">
                <path d="M459.4 151.7c.3 4.5 .3 9.1 .3 13.6 0 138.7-105.6 298.6-298.6 298.6-59.5 0-114.7-17.2-161.1-47.1 8.4 1 16.6 1.3 25.3 1.3 49.1 0 94.2-16.6 130.3-44.8-46.1-1-84.8-31.2-98.1-72.8 6.5 1 13 1.6 19.8 1.6 9.4 0 18.8-1.3 27.6-3.6-48.1-9.7-84.1-52-84.1-103v-1.3c14 7.8 30.2 12.7 47.4 13.3-28.3-18.8-46.8-51-46.8-87.4 0-19.5 5.2-37.4 14.3-53 51.7 63.7 129.3 105.3 216.4 109.8-1.6-7.8-2.6-15.9-2.6-24 0-57.8 46.8-104.9 104.9-104.9 30.2 0 57.5 12.7 76.7 33.1 23.7-4.5 46.5-13.3 66.6-25.3-7.8 24.4-24.4 44.8-46.1 57.8 21.1-2.3 41.6-8.1 60.4-16.2-14.3 20.8-32.2 39.3-52.6 54.3z" />
            </symbol>
            <symbol viewBox="0 0 448 512" id="vimeo">
                <path d="M403.2 32H44.8C20.1 32 0 52.1 0 76.8v358.4C0 459.9 20.1 480 44.8 480h358.4c24.7 0 44.8-20.1 44.8-44.8V76.8c0-24.7-20.1-44.8-44.8-44.8zM377 180.8c-1.4 31.5-23.4 74.7-66 129.4-44 57.2-81.3 85.8-111.7 85.8-18.9 0-34.8-17.4-47.9-52.3-25.5-93.3-36.4-148-57.4-148-2.4 0-10.9 5.1-25.4 15.2l-15.2-19.6c37.3-32.8 72.9-69.2 95.2-71.2 25.2-2.4 40.7 14.8 46.5 51.7 20.7 131.2 29.9 151 67.6 91.6 13.5-21.4 20.8-37.7 21.8-48.9 3.5-33.2-25.9-30.9-45.8-22.4 15.9-52.1 46.3-77.4 91.2-76 33.3 .9 49 22.5 47.1 64.7z" />
            </symbol>
            <symbol viewBox="0 0 512 512" id="weibo">
                <path d="M407 177.6c7.6-24-13.4-46.8-37.4-41.7-22 4.8-28.8-28.1-7.1-32.8 50.1-10.9 92.3 37.1 76.5 84.8-6.8 21.2-38.8 10.8-32-10.3zM214.8 446.7C108.5 446.7 0 395.3 0 310.4c0-44.3 28-95.4 76.3-143.7C176 67 279.5 65.8 249.9 161c-4 13.1 12.3 5.7 12.3 6 79.5-33.6 140.5-16.8 114 51.4-3.7 9.4 1.1 10.9 8.3 13.1 135.7 42.3 34.8 215.2-169.7 215.2zm143.7-146.3c-5.4-55.7-78.5-94-163.4-85.7-84.8 8.6-148.8 60.3-143.4 116s78.5 94 163.4 85.7c84.8-8.6 148.8-60.3 143.4-116zM347.9 35.1c-25.9 5.6-16.8 43.7 8.3 38.3 72.3-15.2 134.8 52.8 111.7 124-7.4 24.2 29.1 37 37.4 12 31.9-99.8-55.1-195.9-157.4-174.3zm-78.5 311c-17.1 38.8-66.8 60-109.1 46.3-40.8-13.1-58-53.4-40.3-89.7 17.7-35.4 63.1-55.4 103.4-45.1 42 10.8 63.1 50.2 46 88.5zm-86.3-30c-12.9-5.4-30 .3-38 12.9-8.3 12.9-4.3 28 8.6 34 13.1 6 30.8 .3 39.1-12.9 8-13.1 3.7-28.3-9.7-34zm32.6-13.4c-5.1-1.7-11.4 .6-14.3 5.4-2.9 5.1-1.4 10.6 3.7 12.9 5.1 2 11.7-.3 14.6-5.4 2.8-5.2 1.1-10.9-4-12.9z" />
            </symbol>
            <symbol viewBox="0 0 576 512" id="weixin">
                <path d="M385.2 167.6c6.4 0 12.6 .3 18.8 1.1C387.4 90.3 303.3 32 207.7 32 100.5 32 13 104.8 13 197.4c0 53.4 29.3 97.5 77.9 131.6l-19.3 58.6 68-34.1c24.4 4.8 43.8 9.7 68.2 9.7 6.2 0 12.1-.3 18.3-.8-4-12.9-6.2-26.6-6.2-40.8-.1-84.9 72.9-154 165.3-154zm-104.5-52.9c14.5 0 24.2 9.7 24.2 24.4 0 14.5-9.7 24.2-24.2 24.2-14.8 0-29.3-9.7-29.3-24.2 .1-14.7 14.6-24.4 29.3-24.4zm-136.4 48.6c-14.5 0-29.3-9.7-29.3-24.2 0-14.8 14.8-24.4 29.3-24.4 14.8 0 24.4 9.7 24.4 24.4 0 14.6-9.6 24.2-24.4 24.2zM563 319.4c0-77.9-77.9-141.3-165.4-141.3-92.7 0-165.4 63.4-165.4 141.3S305 460.7 397.6 460.7c19.3 0 38.9-5.1 58.6-9.9l53.4 29.3-14.8-48.6C534 402.1 563 363.2 563 319.4zm-219.1-24.5c-9.7 0-19.3-9.7-19.3-19.6 0-9.7 9.7-19.3 19.3-19.3 14.8 0 24.4 9.7 24.4 19.3 0 10-9.7 19.6-24.4 19.6zm107.1 0c-9.7 0-19.3-9.7-19.3-19.6 0-9.7 9.7-19.3 19.3-19.3 14.5 0 24.4 9.7 24.4 19.3 .1 10-9.9 19.6-24.4 19.6z" />
            </symbol>
            <symbol viewBox="0 0 448 512" id="x-twitter">
                <path d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zm297.1 84L257.3 234.6 379.4 396H283.8L209 298.1 123.3 396H75.8l111-126.9L69.7 116h98l67.7 89.5L313.6 116h47.5zM323.3 367.6L153.4 142.9H125.1L296.9 367.6h26.3z" />
            </symbol>
            <symbol viewBox="0 0 576 512" id="youtube">
                <path d="M549.7 124.1c-6.3-23.7-24.8-42.3-48.3-48.6C458.8 64 288 64 288 64S117.2 64 74.6 75.5c-23.5 6.3-42 24.9-48.3 48.6-11.4 42.9-11.4 132.3-11.4 132.3s0 89.4 11.4 132.3c6.3 23.7 24.8 41.5 48.3 47.8C117.2 448 288 448 288 448s170.8 0 213.4-11.5c23.5-6.3 42-24.2 48.3-47.8 11.4-42.9 11.4-132.3 11.4-132.3s0-89.4-11.4-132.3zm-317.5 213.5V175.2l142.7 81.2-142.7 81.2z" />
            </symbol>
            <symbol viewBox="0 0 640 512" id="zhihu">
                <path d="M170.5 148.1v217.5l23.4 0 7.7 26.4 42-26.4h49.5V148.1H170.5zm97.8 193.9h-27.9l-27.9 17.5-5.1-17.5-11.9 0V171.8h72.8v170.3zm-118.5-94.4H97.5c1.7-27.1 2.2-51.6 2.2-73.5h51.2s2-22.6-8.6-22.3h-88.5c3.5-13.1 7.9-26.7 13.1-40.7 0 0-24.1 0-32.3 21.6-3.4 8.9-13.2 43.1-30.7 78.1 5.9-.6 25.4-1.2 36.8-22.2 2.1-5.9 2.5-6.7 5.1-14.5h28.9c0 10.5-1.2 66.9-1.7 73.4H20.8c-11.7 0-15.6 23.6-15.6 23.6h65.6C66.5 321.1 42.8 363.1 0 396.3c20.5 5.9 40.9-.9 51-9.9 0 0 23-20.9 35.6-69.3l54 64.9s7.9-26.9-1.2-40c-7.6-8.9-28.1-33.1-36.8-41.8L87.9 312c4.4-14 7-27.6 7.9-40.7h61.7s-.1-23.6-7.6-23.6v0zm412-1.6c20.8-25.6 45-58.6 45-58.6s-18.7-14.8-27.4-4.1c-6 8.2-36.8 48.2-36.8 48.2l19.2 14.4zm-150.1-59.1c-9-8.3-25.9 2.1-25.9 2.1s39.5 55 41.1 57.5l19.5-13.7s-25.7-37.6-34.7-45.9h0zM640 258.4c-19.8 0-130.9 .9-131.1 .9v-101c4.8 0 12.4-.4 22.9-1.2 40.9-2.4 70.1-4 87.8-4.8 0 0 12.2-27.2-.6-33.4-3.1-1.2-23.2 4.6-23.2 4.6s-165.2 16.5-232.4 18.1c1.6 8.8 7.6 17.1 15.8 19.6 13.3 3.5 22.7 1.7 49.2 .9 24.8-1.6 43.7-2.4 56.5-2.4v99.8H351.4s2.8 22.3 25.5 22.9h107.9v70.9c0 14-11.2 22-24.5 21.1-14.1 .1-26.1-1.2-41.7-1.8 2 4 6.3 14.4 19.3 21.8 9.9 4.8 16.2 6.6 26 6.6 29.6 0 45.7-17.3 44.9-45.3v-73.3h122.4c9.7 0 8.7-23.8 8.7-23.8l0 0z" />
            </symbol>
        </svg>
    </body>
</html>

在我们继续之前,我想解释一下上面代码片段中的 class="sr-only" 。通过 CSS 为 .sr-only 定义一段样式来隐藏 SVG。

CSS
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
}

虽然说,<symbol> 不会在 SVG 画布上呈现任何内容,但 <svg> 仍然会占用页面上的空间(将 <svg> 嵌套在 HTML 文档中),导致出现一个大的空白区域,有可能会打破你的 Web 布局。为了避免这种情况,我们通过 .sr-only 中的样式隐藏 SVG,使其在页面上不占任何空间。需要知道的是,这样做并不会影响 SVG 雪碧图的使用效果。

一旦你准备好了 SVG 雪碧图,你就可以通过使用 SVG 的 <use> 元素引用它们,在页面上的任何地方显示图标:

XML
<svg class="icon">
    <use href="#dribbble" />
</svg>

Demo 地址:https://codepen.io/airen/full/GRLMwrq

就是这样!

我们也可以将 SVG 雪碧图保存为单独的 .svg 。例如 icons.svg ,在这个文件中,同样使用 <symbol> 实例化 SVG 图标:

XML
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <symbol viewBox="0 0 448 512" id="dribbble">
        <path d="M165.9 132.5c-38.3 18-66.8 53.3-75.7 95.7c6.1 .1 62.4 .3 126.4-16.7c-22.7-40.2-47.1-74.1-50.7-79zm26.1-9.1c3.8 5.1 28.6 38.9 51 80c48.6-18.3 69.1-45.9 71.6-49.4C281 124.2 235.3 112.9 192 123.4zM277.4 382c-2-12-10-53.8-29.2-103.6c-55.1 18.8-93.8 56.4-108.1 85.6c40.5 31.6 93.3 36.7 137.3 18zM227.8 232.6C159.6 253 93.4 252.2 87.4 252c0 .7 0 1.4 0 2.1s0 1.4 0 2.1c0 35.1 13.3 67.1 35.1 91.4c22.2-37.9 67.1-77.9 116.5-91.8c-3.4-7.8-7.2-15.5-11.1-23.2zm72.5 136.9c30.7-20.7 52.5-53.6 58.6-91.6c-4.6-1.5-42.3-12.7-85.1-5.8c17.9 49.1 25.1 89.1 26.5 97.4zm-34.8-119c45.5-5.7 90.7 3.4 95.2 4.4c-.3-32.3-11.8-61.9-30.9-85.1c-2.9 3.9-25.8 33.2-76.3 53.9c4.8 9.8 8.3 17.8 12 26.8zM384 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64zM224 416a160 160 0 1 1 0-320 160 160 0 1 1 0 320z" />
    </symbol>
    <symbol viewBox="0 0 448 512" id="facebook">
        <path d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64h98.2V334.2H109.4V256h52.8V222.3c0-87.1 39.4-127.5 125-127.5c16.2 0 44.2 3.2 55.7 6.4V172c-6-.6-16.5-1-29.6-1c-42 0-58.2 15.9-58.2 57.2V256h83.6l-14.4 78.2H255V480H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64z" />
    </symbol>
    <!-- 省略其他的 SVG 图标 -->
</svg>    

我们把这种方式称为外部 SVG 雪碧图。与内联 SVG 雪碧图不一样的是,在 HTML 中引用外部 SVG 雪碧图中的图标,需要利用 SVG 片段标识符在雪碧图中选择单个图标。例如:

XML
<svg class="icon">
    <use href="icons.svg#dribbble" />
</svg>
 
<svg class="icon">
    <use href="icons.svg#facebook" />
</svg> 

上面示例中的 icons.svg 是包含所有图标的 SVG 文件的名称(也称外部 SVG 雪碧图),而片段标识符 #dribbble#facebook 分别对应的是 icons.svg 文件中 iddribbblefacebook<symbol>

如果硬编码的方式创建 SVG 雪碧图方式令你感到烦感的话,那么你可以考虑使用工具来帮助你快速创建 SVG 雪碧图。例如 svgsprit.es 可以帮助你快速构建 SVG 雪碧图:

URL:https://svgsprit.es/

虽然这种方式可以帮助你快速获得 SVG 雪碧图,但我们要构建的是 SVG 图标系统,该系统必须具备非规定性、可扩展性。换句话说,我们更希望以自动化的方式来创建 SVG 雪碧图,即它能将 icons 目录下的 SVG 图标生成 SVG 雪碧图。

庆幸的是,有一些工具可以自动化创建 SVG 雪碧图。@Joschi Kuphal 制作了一个很棒的工具 SVG Sprite,他还将其移植到了 Gulp 中,称为 gulp-svg-sprite。SVG Sprite 工具非常棒。它提供了多种 SVG 雪碧图的选项,例如:

  • 传统的 CSS 雪碧图,用于背景图像(background-image
  • 带有预定义的 <view> 元素的 CSS 雪碧图,适应于背景图(background-image),也适应用于 HTML 的 <img>
  • 使用 <defs> 元素创建的内联 SVG 雪碧图
  • 使用 <symbol> 元素创建的内联 SVG 雪碧图
  • SVG 堆栈,图标堆叠在一起

除此之外,还有一些额外的好处,比如为你构建一个参考页。这个参考页相当于 SVG 雪碧图的集成到 Web 应用或网站的使用指南。

假设你为 SVG 图标系统创建了一个名为 svg 的项目,在该项目的根目录下创建一个 icons 文件夹,并把单个 SVG 图标文件放置在 icons 文件夹中。接下来,你就可以通过 SVG Sprite 工具来自动创建 SVG 雪碧图。首先在该项目根目录下创建一个 gulpfile.js 文件,根据 SVG Sprite 工具的使用文档,在 gulpfile.js 文件中配置生成 SVG 雪碧图所需的选项。

JavaScript
'use-strict';
const { src, dest, series } = require('gulp');
const svgSprite = require('gulp-svg-sprite');
 
// 配置参数
const config = {
    mode: {
        // css: true,   // 传统的 CSS 雪碧图,用于背景图像(background-image)
        // view: true,  // 带有预定义的 <view> 元素的 CSS 雪碧图
        // defs: true,  // 使用 <defs> 元素创建的内联 SVG 雪碧图
        // stack: true, // SVG 堆栈雪碧图
        symbol: {       // 使用 <symbol> 元素创建的内联 SVG 雪碧图
            dest: 'sprite',        // 放置生成的 SVG 雪碧图文件夹
            sprite: 'sprite.svg',  // SVG 雪碧图文件名
            example: true          // 生成参考页,使用指南
        }
    },
    svg: {
        xmlDeclaration: false,     // 移除 XML 属性
        doctypeDeclaration: false  // 不包括 DOCTYPE 声明
    }
};
 
function spritePage() {
      return src('icons/**/*.svg') // 放置 SVG 图标文件的路径
          .pipe(svgSprite(config))
          .pipe(dest('.'));
}
 
function spriteShortcut() {
    return src('sprite/sprite.svg') // 生成 SVG 雪碧图
        .pipe(dest('.'));
}
 
exports.default = series(spritePage, spriteShortcut);

配置完 gulpfile.js 之后,你需要在 package.json 文件中配置依赖包和执行脚本:

JSON
{
    "name": "svg",
    "main": "index.js",
    "scripts": {
        "gulp": "gulp",
        "test": "echo "Error: no test specified" && exit 1"
    },
        "devDependencies": {
        "gulp": "^5.0.0",
        "gulp-rename": "^2.0.0",
        "gulp-svg-sprite": "^2.0.3"
    }
}

安装完所需的依赖包之后,在命令终端执行 gulp 命令,就能根据 icons 目录下的 SVG 图标自动生成你所需要的 SVG 雪碧图:

在项目的 sprite 目录下,你可以找到生成后的 sprite.svg 文件:

在这个目录下还为你生成了一个参考页:

接下来,你就可以在项目中通过 <use> 元素以外联 SVG 雪碧图的方式引用所需的 SVG 图标:

XML
<svg class="icon icon--twitter">
    <use href="sprite.svg#twitter" />
</svg>
 
<svg class="icon icon--github">
    <use href="sprite.svg#github" />
</svg>
 
<svg class="icon icon--qq">
    <use href="sprite.svg#qq" />
</svg>

现在,你可以随时往 icons 文件夹中添加 SVG 图标文件。SVG Sprite 的另一个优势是它尊重命名图标的文件夹系统。这意味着,如果我们的基础文件夹是 icons/ ,那么该文件夹中的任何内容都可以通过其名称(SVG 图标文件名)进行引用,而文件夹中的任何内容都将被添加前缀:

plaintext
icons/
|-- twitter.svg  // sprite.svg#twitter
|-- github.svg   // sprite.svg#github
|
|--weather/
|--bolt.svg     // sprite.svg#weather--bolt
|--cloud.svg    // sprite.svg#weather--cloud
|
|--animals
|--feather.svg  // sprite.svg#animals--feather
|--hippo.svg    // sprite.svg#animals--hippo

在考虑这种命名结构时,你现在可以教会你的设计师如何将图标添加到该文件夹并提交拉取请求!效率大大提高!添加新图标时,它们不会影响现有图标,而是增加系统的图标选项:

XML
<!-- 位于 icons 目录下的 SVG 图标 -->
<svg class="icon icon--twitter">
    <use href="sprite.svg#twitter" />
</svg>
 
<svg class="icon icon--github">
    <use href="sprite.svg#github" />
</svg>
 
<!-- 位于 icons/animals 目录下的 SVG 图标 -->
<svg class="icon icon--feather">
    <use href="sprite.svg#animals--feather" />
</svg>
 
<svg class="icon icon--hippo">
    <use href="sprite.svg#animals--hippo" />
</svg>
 
<!-- 位于 icons/weather 目录下的 SVG 图标 -->
<svg class="icon icon--umbrella">
    <use href="sprite.svg#weather--umbrella" />
</svg>
 
<svg class="icon icon--snowflake">
    <use href="sprite.svg#weather--snowflake" />
</svg>

具备了自动化生成 SVG 雪碧图能力之后,你不用再担心有新的 SVG 图标加入了。

注意,在这里我们仅演示了 SVG Sprite 工具中的 gulp-svg-sprite 是如何自动生成 SVG 雪碧图的。类似这样的工具和工程能力还有很多,比如 Webpack、Vite 等,它们可以帮助你快速生成 SVG 雪碧图。在后续的实战课程中还将涉及这方面的内容。这里就不做更多的阐述。

使用 SVG 图标

生成的 SVG 雪碧图,我们有多种方式可以被引用到 Web 应用或网站,常见的方式分为内联和外联 SVG 雪碧图。其中内联的方式指的是将生成的 SVG 雪碧图文件(sprite.svg)对应的 SVG 代码,直接复制粘贴到你的 HTML 文档中,例如:

HTML
<body>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="sr-only">
        <symbol viewBox="0 0 512 512" id="animals--feather">
            <path d="M278.5 215.6 23 471c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l57-57h68c49.7 0 97.9-14.4 139-41 11.1-7.2 5.5-23-7.8-23-5.1 0-9.2-4.1-9.2-9.2 0-4.1 2.7-7.6 6.5-8.8l81-24.3c2.5-.8 4.8-2.1 6.7-4l22.4-22.4c10.1-10.1 2.9-27.3-11.3-27.3H377c-5.1 0-9.2-4.1-9.2-9.2 0-4.1 2.7-7.6 6.5-8.8l112-33.6c4-1.2 7.4-3.9 9.3-7.7 10.8-21 16.4-44.5 16.4-68.6 0-41-16.3-80.3-45.3-109.3l-5.5-5.5C432.3 16.3 393 0 352 0s-80.3 16.3-109.3 45.3L139 149c-48 48-75 113.1-75 181v55.3l189.6-189.5c6.2-6.2 16.4-6.2 22.6 0 5.4 5.4 6.1 13.6 2.2 19.8z"/>
        </symbol>
        <!-- 省略其他 symbol -->
    </svg>
</body>

此时,你在 HTML 文档中,可以直接使用 <use> 来引用所需的 SVG 图标:

XML
<svg class="icon icon--feather">
    <use href="#animals--feather" />
</svg>

Demo 地址:https://codepen.io/airen/full/poBWXBx

外联 SVG 雪碧图的使用方式与内联 SVG 雪碧图方式有点相似,唯一不同的是,SVG 雪碧图是以文件引入的方式加载到 Web 应用或网站的。

XML
<svg class="icon icon--twitter">
    <use href="sprite.svg#twitter" />
</svg>

看上去是不是与 <img> 为 Web 添加图片的方式相似。

如果你采用的是外联 SVG 雪碧图的方式,那么建议你对 sprite.svg 做一个预加载的处理。你可以使用 <link> 标签的 preload 功能,将 sprite.svg 文件添加到 <head> 中:

HTML
<!DOCTYPE html>
<html lang="en">
    <head>
        <link rel="preload" href="sprite.svg"  />
    </head>
    <body>
        <svg class="icon icon--twitter">
            <use href="sprite.svg#twitter" />
        </svg>
    </body>
</html>    

这是在性能优化上的一个小细节,过多就不在这里阐述了。这里不对两种使用方式做对比,仅从我个人喜好出好,我自己更喜欢使用内联 SVG 雪碧图的方式。

在实际应用的时候,我们还可以考虑 SVG 图标可访问性,它不会额外为你增添加太多工作量,但对于你的应用有较多的好处,比如,使每一位访问你的应用的用户都有平等、统一的体验。

HTML
<button type="button">
    <svg role="img" class="icon icon--twitter" aria-labelledby="button-title" focusable="false">
        <title id="button-title">Twitter</title>
        <use href="#twitter" />
    </svg>
</button>
 
<a href="#">
    <svg role="img" class="icon icon--twitter" aria-labelledby="link-title" focusable="false">
        <title id="link-title">Jump to Twitter</title>
        <use xlink:href="#twitter" />
    </svg>
</a>
 
<button type="button">
    <svg class="icon icon--twitter" aria-hidden="true" focusable="false">
        <use xlink:href="#twitter" />
    </svg>
    Twitter
</button>
 
<a href="#">
    Jump to Twitter
    <svg class="icon icon--twitter" aria-hidden="true" focusable="false">
        <use xlink:href="#twitter" />
    </svg>
</a>

上面代码所展示的几种方式,都是使 SVG 图标在被应用时更具可访问性,易于辅助技术(例如屏幕阅读器)识别。

也有一些人建议在创建 SVG 雪碧图时,在每个 <symbol> 中放置一个 <title> 元素,对 SVG 图标进行描述。但我不建议这么做,因为我认为这是一个错误的做法。以“放大镜”这个图标为例,当它放在不同的上下文中时,所代表的含义就有可能不同。它有可能是“显示搜索结果”,也有可能是“提交搜索查询”。因此,你的文本标签应该是“显示搜索结果”和“提交搜索查询”,而不是“搜索”(太通用了),千万别写“放大镜图标”,这是非常不好的做法(仅描述了图标的视觉效果,并没有表达图标在上下文中的含义)。这意味着,如果你在 <symbol> 中使用 <title> 对“放大镜”图标进行任何描述,它都很难与上下文所表达的意思相匹配。

非常不幸的是,以 <symbol> 方式创建的 SVG 雪碧图不能用于 HTML 的 <img> 元素,也不能用于 CSS 的 background-image 。但可以以传统的 CSS 雪碧图的方式来使用 SVG 雪碧图。换句话说,我们依旧可以将所有 SVG 图标拼接在一起,并以 SVG 雪碧图的方式存在,然后将其应用于 CSS 的 background-image

继续以 SVG Sprite 工具为例,它就提供了 css 模式,将 icons 目录下的所有 SVG 图标自动生成一张 SVG 雪碧图,它但不是以 <symbol> 方式实例化的,而是以 <svg> 方式存在的。你只需在 gulpfile.js 配置文件中开启 css 模式的配置:

JavaScript
const config = {
    mode: {
        css:{
            render: {
                css: true
            },
            dest: 'sprite',
            sprite: 'sprite.svg',
            example: true 
        },
   }
};

生成的 SVG 雪碧图如下:

XML
<svg width="3328" height="2560" viewBox="0 0 3328 2560" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <svg viewBox="0 0 512 512" width="512" height="512" id="animals--feather" x="1152" y="1024" xmlns="http://www.w3.org/2000/svg">
        <path d="M278.5 215.6 23 471c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l57-57h68c49.7 0 97.9-14.4 139-41 11.1-7.2 5.5-23-7.8-23-5.1 0-9.2-4.1-9.2-9.2 0-4.1 2.7-7.6 6.5-8.8l81-24.3c2.5-.8 4.8-2.1 6.7-4l22.4-22.4c10.1-10.1 2.9-27.3-11.3-27.3H377c-5.1 0-9.2-4.1-9.2-9.2 0-4.1 2.7-7.6 6.5-8.8l112-33.6c4-1.2 7.4-3.9 9.3-7.7 10.8-21 16.4-44.5 16.4-68.6 0-41-16.3-80.3-45.3-109.3l-5.5-5.5C432.3 16.3 393 0 352 0s-80.3 16.3-109.3 45.3L139 149c-48 48-75 113.1-75 181v55.3l189.6-189.5c6.2-6.2 16.4-6.2 22.6 0 5.4 5.4 6.1 13.6 2.2 19.8z"/>
    </svg>
    <!-- 省略其他 SVG 图标 -->
</svg>

然后,你就可以在 CSS 中像下面这样引用 SVG 图标:

HTML
<div class="icon--feather"></div>
CSS
.icon--feather {
    display: block;
    background: url("sprite.svg") 40.90909090909091% 50% no-repeat;
    background-size: 3328px 2560px !important;
    width: 512px;
    height: 512px;
}

你甚至还可以使用 eeencode 工具,将生成的 sprite.svg (雪碧图)文件转换成 Data URI,并在 CSS 中引用指定的 SVG 图标:

URL:https://fffuel.co/eeencode/

HTML
<div class="icon--twitter"></div>
CSS
:root {
    --sprite: url("data:image/svg+xml;base64,PHN2...");
}
 
.icon--twitter {
    background: var(--sprite) 35.79545454545455% 100% no-repeat;
    background-size: 3328px 2560px !important;
    width: 512px;
    height: 512px;
}

在这种情况下,SVG 雪碧图实际上是一张图片,而不是一个 SVG 容器,图标的使用方式与 CSS 雪碧图非常相似,图标作为背景图像提供。这种技术最大的缺点是,以背景图像嵌入的 SVG 无法使用 CSS 进行样式化。另外就是,每个图标的定位(background-position)和适配性都没有内联和外联 SVG 雪碧图那样灵活。

除了上面所提到的使用方式之外,我们还可以使用 SVG 的堆叠和视图的技术。首先来看 SVG 堆叠的技术,它将 icons 目录下所有 SVG 图标叠在一起,并且默认所有 SVG 雪碧图中所有图标都不可见,只有被 SVG 片段符选中的图标才可见。

同样可以使用 SVG Sprite 工具,将 icons 文件夹下所有图标堆叠在一起:

JavaScript
// gulpfile.js
const config = {
    mode: {
        stack: {
            dest: 'sprite',
            sprite: 'sprite.svg', 
            example: true 
        }
    }
};

生成的 sprite.svg 代码如下:

XML
<svg viewBox="0 0 640 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <style>
        :root > svg{
            display:none
        }
        :root > svg:target{
            display:block
        }
    </style>
    <svg viewBox="0 0 512 512" id="animals--feather" xmlns="http://www.w3.org/2000/svg">
        <path d="M278.5 215.6 23 471c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l57-57h68c49.7 0 97.9-14.4 139-41 11.1-7.2 5.5-23-7.8-23-5.1 0-9.2-4.1-9.2-9.2 0-4.1 2.7-7.6 6.5-8.8l81-24.3c2.5-.8 4.8-2.1 6.7-4l22.4-22.4c10.1-10.1 2.9-27.3-11.3-27.3H377c-5.1 0-9.2-4.1-9.2-9.2 0-4.1 2.7-7.6 6.5-8.8l112-33.6c4-1.2 7.4-3.9 9.3-7.7 10.8-21 16.4-44.5 16.4-68.6 0-41-16.3-80.3-45.3-109.3l-5.5-5.5C432.3 16.3 393 0 352 0s-80.3 16.3-109.3 45.3L139 149c-48 48-75 113.1-75 181v55.3l189.6-189.5c6.2-6.2 16.4-6.2 22.6 0 5.4 5.4 6.1 13.6 2.2 19.8z"/>
    </svg>
    <svg viewBox="0 0 640 512" id="animals--hippo" xmlns="http://www.w3.org/2000/svg">
        <path d="M407 47c9.4-9.4 24.6-9.4 33.9 0l17.2 17.2c1.9-.1 3.9-.2 5.8-.2h32c11.2 0 21.9 2.3 31.6 6.5L543 55c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-12.9 13c7.6 12.2 12 26.7 12 42.1 0 10.2 7.4 18.8 16.7 23 27.9 12.5 47.3 40.5 47.3 73 0 26.2-12.6 49.4-32 64v32c0 8.8-7.2 16-16 16h-32c-8.8 0-16-7.2-16-16v-16h-64v16c0 8.8-7.2 16-16 16h-32c-8.8 0-16-7.2-16-16v-17.6c-11.8-2.4-22.7-7.4-32-14.4-1.5-1.1-2.9-2.3-4.3-3.5-17-14.7-27.7-36.4-27.7-60.5 0-8.8-7.2-16-16-16s-16 7.2-16 16c0 44.7 26.2 83.2 64 101.2V352c0 17.7 14.3 32 32 32h32v64c0 17.7-14.3 32-32 32h-64c-17.7 0-32-14.3-32-32v-76c-19.8 7.7-41.4 12-64 12s-44.2-4.3-64-12v76c0 17.7-14.3 32-32 32H96c-17.7 0-32-14.3-32-32V329.1l-18.1 40.6c-5.4 12.1-19.6 17.6-31.7 12.2s-17.5-19.5-12.1-31.6L24 300.9c5.3-11.9 8-24.7 8-37.7C32 155.7 117.2 68 223.8 64.1l.2-.1h64c41.7 0 83.4 12.1 117.2 25.7 1.7-1.8 3.5-3.6 5.3-5.2L407 81c-9.4-9.4-9.4-24.6 0-33.9zm73 185a24 24 0 1 0-48 0 24 24 0 1 0 48 0zm88 24a24 24 0 1 0 0-48 24 24 0 1 0 0 48zm-88-112a16 16 0 1 0-32 0 16 16 0 1 0 32 0zm48 16a16 16 0 1 0 0-32 16 16 0 1 0 0 32z"/>
    </svg>
    <!-- 省略其他 SVG 图标 -->
</svg>

这个时候,你可以像下面这样在 HTML 和 CSS 使用 sprite.svg 中的图标:

HTML
<body>
    <img src="sprite-stack.svg#twitter" alt="" />
    <img src="sprite-stack.svg#github" alt="" />
    <div class="icon icon--hippo"></div>
    <div class="icon icon--umbrella"></div>
</body>
CSS
body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100% - 2rem, 300px), 1fr));
    gap: 2rem;
}
 
.icon, img {
    display: block;
    width: 100%;
    aspect-ratio: 1;
}
 
.icon--hippo {
    background: url("sprite-stack.svg#animals--hippo") no-repeat;
}
 
.icon--umbrella {
    background: url("sprite-stack.svg#weather--umbrella") no-repeat;
}

最后一种是 SVG 视图(<view> )的使用方式。

JavaScript
// gulpfile.js
const config = {
    mode: {
        view: {
            dest: 'sprite', 
            sprite: 'sprite.svg', 
            example: true 
        },
    }
};

生成的 sprite.svg 中会有一个带有 id 名的 <view>

XML
<svg width="3328" height="2560" viewBox="0 0 3328 2560" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <view id="animals--feather" viewBox="1152 1024 512 512"/>
    <svg viewBox="0 0 512 512" width="512" height="512" x="1152" y="1024" xmlns="http://www.w3.org/2000/svg">
        <path d="M278.5 215.6 23 471c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l57-57h68c49.7 0 97.9-14.4 139-41 11.1-7.2 5.5-23-7.8-23-5.1 0-9.2-4.1-9.2-9.2 0-4.1 2.7-7.6 6.5-8.8l81-24.3c2.5-.8 4.8-2.1 6.7-4l22.4-22.4c10.1-10.1 2.9-27.3-11.3-27.3H377c-5.1 0-9.2-4.1-9.2-9.2 0-4.1 2.7-7.6 6.5-8.8l112-33.6c4-1.2 7.4-3.9 9.3-7.7 10.8-21 16.4-44.5 16.4-68.6 0-41-16.3-80.3-45.3-109.3l-5.5-5.5C432.3 16.3 393 0 352 0s-80.3 16.3-109.3 45.3L139 149c-48 48-75 113.1-75 181v55.3l189.6-189.5c6.2-6.2 16.4-6.2 22.6 0 5.4 5.4 6.1 13.6 2.2 19.8z"/>
    </svg>
 
    <view id="animals--hippo" viewBox="0 0 640 512"/>
    <svg viewBox="0 0 640 512" width="640" height="512" xmlns="http://www.w3.org/2000/svg">
        <path d="M407 47c9.4-9.4 24.6-9.4 33.9 0l17.2 17.2c1.9-.1 3.9-.2 5.8-.2h32c11.2 0 21.9 2.3 31.6 6.5L543 55c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-12.9 13c7.6 12.2 12 26.7 12 42.1 0 10.2 7.4 18.8 16.7 23 27.9 12.5 47.3 40.5 47.3 73 0 26.2-12.6 49.4-32 64v32c0 8.8-7.2 16-16 16h-32c-8.8 0-16-7.2-16-16v-16h-64v16c0 8.8-7.2 16-16 16h-32c-8.8 0-16-7.2-16-16v-17.6c-11.8-2.4-22.7-7.4-32-14.4-1.5-1.1-2.9-2.3-4.3-3.5-17-14.7-27.7-36.4-27.7-60.5 0-8.8-7.2-16-16-16s-16 7.2-16 16c0 44.7 26.2 83.2 64 101.2V352c0 17.7 14.3 32 32 32h32v64c0 17.7-14.3 32-32 32h-64c-17.7 0-32-14.3-32-32v-76c-19.8 7.7-41.4 12-64 12s-44.2-4.3-64-12v76c0 17.7-14.3 32-32 32H96c-17.7 0-32-14.3-32-32V329.1l-18.1 40.6c-5.4 12.1-19.6 17.6-31.7 12.2s-17.5-19.5-12.1-31.6L24 300.9c5.3-11.9 8-24.7 8-37.7C32 155.7 117.2 68 223.8 64.1l.2-.1h64c41.7 0 83.4 12.1 117.2 25.7 1.7-1.8 3.5-3.6 5.3-5.2L407 81c-9.4-9.4-9.4-24.6 0-33.9zm73 185a24 24 0 1 0-48 0 24 24 0 1 0 48 0zm88 24a24 24 0 1 0 0-48 24 24 0 1 0 0 48zm-88-112a16 16 0 1 0-32 0 16 16 0 1 0 32 0zm48 16a16 16 0 1 0 0-32 16 16 0 1 0 0 32z"/>
    </svg>
    <!-- 省略其他 SVG 图标 -->
</svg>

你会发现,一个 SVG 图标对应一个 <svg><view> 元素。然后你可以像下面这样使用:

HTML
<img src="sprite-view-25133bf8.svg#twitter" alt="" style="aspect-ratio: 512 / 512"  />
<img src="sprite-view-25133bf8.svg#svgView(viewBox(0 ,0, 640, 512))" alt="" style="aspect-ratio: 640 / 512;" />
<div class="icon icon--spider"></div>
<div class="icon icon--facebook"></div>
CSS
body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100% - 2rem, 300px), 1fr));
    gap: 2rem;
}
 
.icon, img {
    display: block;
    width: 100%;
}
 
.icon {
    background-size: 100% 100% !important;
}
 
img {
    object-fit: cover;
}
 
.icon--spider {
    background: url("sprite-view-25133bf8.svg#animals--spider") no-repeat;
    aspect-ratio: 1;
}
 
.icon--facebook {
    background: url("sprite-view-25133bf8.svg#svgView(viewBox(1856, 1024, 448, 512))") no-repeat;
    aspect-ratio: 448 / 512;
}        

这种技术将使用 SVG 的 viewBox 属性将 SVG 雪碧图裁剪到指定的图标。这种技术 除了能够引用外部 SVG 并因此利用浏览器缓存之外,它还允许我们使用几乎任何 SVG 嵌入技术,并且不限制我们使用特定的标签。不用说,这个功能不仅可以用于图标系统,还可以用于其他用途,因为 viewBox 在控制SVG的可视区域方面非常强大。

使用 SVG 片段标识符和视图与 CSS 内联 SVG 雪碧图上样,我们无法直接使用 CSS 对 SVG 进行样式设置。

使用 CSS 样式化图标

首先需要明确的一点是,如果我们要将 SVG 雪碧图的图标以内联 CSS 的方式或 SVG 片段标识符的方式应用于 Web,那么直接使用 SVG 元素的“演示属性”来为SVG图标设置样式就会变得相对困难。不过,你可以借助现代 CSS 特性中的处理图像特效的相关属性(如 filtermix-blend-modebackground-blend-mode 等)来调整图标的样式。例如下面这个示例是使用 filter 调整 SVG 图标的颜色:

HTML
<div class="icon"></div>
CSS
:root {
    --icon: url("data:image/svg+xml;base64,PD94bWw...");
}
 
.icon {
    --invert: 0;
    --sepia: 0;
    --saturate: 1;
    --hueRotate: 0;
    --brightness: 1;
    filter: invert(var(--invert)) sepia(var(--sepia)) saturate(var(--saturate))
      hue-rotate(calc(var(--hueRotate) * 1turn)) brightness(var(--brightness));
}

Demo 地址:https://codepen.io/airen/full/oNOovrV

接下来,我们着重聊聊 CSS 如何给内联 SVG 雪碧图设置样式。

HTML
<body>
    <!-- 引用 SVG 图标 -->
    <svg class="icon icon--dribbble">
        <use href="#dribbble" />
    </svg>    
 
    <!-- 创建 SVG 雪碧图 -->
    <svg class="sr-only">
        <symbol viewBox="0 0 448 512" id="dribbble">
            <path d="M165.9 132.5c-38.3 18-66.8 53.3-75.7 95.7c6.1 .1 62.4 .3 126.4-16.7c-22.7-40.2-47.1-74.1-50.7-79zm26.1-9.1c3.8 5.1 28.6 38.9 51 80c48.6-18.3 69.1-45.9 71.6-49.4C281 124.2 235.3 112.9 192 123.4zM277.4 382c-2-12-10-53.8-29.2-103.6c-55.1 18.8-93.8 56.4-108.1 85.6c40.5 31.6 93.3 36.7 137.3 18zM227.8 232.6C159.6 253 93.4 252.2 87.4 252c0 .7 0 1.4 0 2.1s0 1.4 0 2.1c0 35.1 13.3 67.1 35.1 91.4c22.2-37.9 67.1-77.9 116.5-91.8c-3.4-7.8-7.2-15.5-11.1-23.2zm72.5 136.9c30.7-20.7 52.5-53.6 58.6-91.6c-4.6-1.5-42.3-12.7-85.1-5.8c17.9 49.1 25.1 89.1 26.5 97.4zm-34.8-119c45.5-5.7 90.7 3.4 95.2 4.4c-.3-32.3-11.8-61.9-30.9-85.1c-2.9 3.9-25.8 33.2-76.3 53.9c4.8 9.8 8.3 17.8 12 26.8zM384 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64zM224 416a160 160 0 1 1 0-320 160 160 0 1 1 0 320z" />
        </symbol>
        <symbol viewBox="0 0 448 512" id="facebook">
            <path d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64h98.2V334.2H109.4V256h52.8V222.3c0-87.1 39.4-127.5 125-127.5c16.2 0 44.2 3.2 55.7 6.4V172c-6-.6-16.5-1-29.6-1c-42 0-58.2 15.9-58.2 57.2V256h83.6l-14.4 78.2H255V480H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64z" />
        </symbol>
        <!-- 其他 SVG 图标 -->
    </svg>
</body>

我们从基础样式开始。示例在给 SVG 雪碧图添加了一个 sr-only 类名,使用 SVG 图标时添加了一个 icon 类名。在 CSS 中给这两个通用类设置了以下样式:

CSS
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
}
 
.icon {
    display: block;
    width: 1em;
    aspect-ratio: var(--ratio, 1); /* 对应 viewBox 中的 width 和 height*/
    fill: currentColor;
}

.sr-only 主要是为了隐藏 SVG 雪碧图,这样做是使 SVG 雪碧图不占用页面的任何空间(虽然 <symbol> 绘制的图标不会在 SVG 画布上呈现),避免打破 Web 布局。

.icon 是应用图标的基本样式。<svg> 元素的 vertical-align 默认值是 baseline ,这会在图标留下几个像素的空白(大约是 4px)。可以通过重置 display 的值为 block 来避免这种情况出现。除此之外,你还可以显示设置 vertical-align 的值,只要不是默认值 baseline 即可。如果与文本一起使用,你可以将 vertical-align 设置为 -4px (或 -0.15em)。

通常情况下,<symbol> 创建的 SVG 图标是以 viewBox 中的 <width><height> 来定义图标的尺寸大小。可以在通用类名 .icon 中使用 widthaspect-ratio 来设置图标的尺寸大小。

CSS
.icon {
    width: 1em;
    aspect-ratio: var(--ratio, 1);
}

上面这样设置,SVG 图标会随着元素的 font-size 调整大小,注意,aspect-ratio 的值最好与 <symbol> 元素的 viewBox 中的 <width><height> 值相匹配。

fill:currentColor 使得 SVG 图标的颜色与 color 同步:

CSS
.icon--dribbble {
    color: lime; 
}
 
.icon--facebook {
    color: red;
}

Demo 地址:https://codepen.io/airen/full/mdgqdpE

正如你所看到的,我们现在只需要调整 font-size 就可以改变图标的大小,调整 color 就可以改变图标的颜色。

另外,SVG 样式属性是可继承的,例如上面示例中的 fill 属性。当我们在 <svg> 元素上设置 fill 属性的值,它的后代元素(如示例中的 <path>)元素也会继承它的值。如此一来,使用这个技术,可以在 CSS 中处理图标的其他样式,例如描边样式:

CSS
.icon {
    fill: none;
    stroke: currentColor;
    stroke-width: 10px;
    stroke-linecap: round;
    stroke-linejoin: round;
}

Demo 地址:https://codepen.io/airen/full/mdgqdGO

细心的你可能已经发现了,上面示例中图标描边的效果并不怎么均匀,看上去有部分被裁剪了一样。这是因为,在 SVG 中,描边总是在路径的两侧(内部和外部)绘制。如果你的路径接触到视口的限制,一半的描边将被裁剪掉。这也是为什么在设计 SVG 图标的时,要在绘制的形状周围留出一些空间的原因所在。

另外,给 SVG 描边设置合适的大小是技术活。例如,下面这个示例,在 <svg> 图标上设置了 stroke-width: 1px

XML
<svg class="sr-only">
    <symbol id="heart" viewBox="0 0 20 20">
        <path d="M18.98 5.7c-.24-2.36-2.24-4.2-4.66-4.2-1.95 0-3.6 1.18-4.32 2.87-.7-1.7-2.37-2.87-4.32-2.87-2.42 0-4.42 1.84-4.66 4.2L1 6.18c0 5.7 6.98 8.38 9 12.17 2.02-3.8 9-6.48 9-12.17 0-.16 0-.32-.02-.48z" />
    </symbol>
    <symbol id="heart2" viewBox="0 0 500 500">
        <path d="M474.4 142.8c-6-59-55.8-105-116.5-105-48.6 0-90.3 29.5-108 71.7-17.7-42.2-59.4-71.8-108-71.8-60.6 0-110.4 46-116.4 105-.4 4-.6 8-.6 12C25 297 199.5 364.3 250 459c50.5-94.8 225-162 225-304.2 0-4-.2-8-.6-12z" />
    </symbol>
</svg>
 
<svg class="icon icon--heart">
    <use href="#heart" />
</svg>
 
<svg class="icon icon--heart2">
    <use href="#heart2" />
</svg>
CSS
.icon {
    stroke-width: 1px;
}

Demo 地址:https://codepen.io/airen/full/OJGOPQw

不难发现,stroke-width 接受同一个“长度”值 1px ,左侧描边比右侧描边明显要粗很多。这是因为该值相对于图标的局部坐标:

  • 左侧图标的 viewBox0 0 20 20 ,因此,1px 的描边是图标尺寸的 1/20viewBox 要填满整个 Viewport,因此会放大,相应的图形也会放大,描边也相应的变粗
  • 右侧图标的 viewBox0 0 500 500 ,因此, 1px 的描边是图标尺寸的 1/500viewBox 要相应缩小才可以填满整个 Viewport,相应的图形也会缩小,描边也相应的变细

这意味着,如果图标的 viewBox 大小差异很大,stroke-width 使用像素或无单位的值,就会出现上面示例这种现象。在这种情景中,可以考虑将 stroke-width 的值设置为百分比值(%)。但需要知道 stroke-width 取百分比值是如何计算的?

事实证明,stroke-width 取百分比值时,它是相对于 viewBox 对角线的长度计算(sqrt((width)**2 + (height)**2)/sqrt(2) ,其中 widthheight 分别是 viewBox 属性的 <width><height>)。当 viewBox 是一个正方形,该公式的结果是正方形的一边。因此,1% 表示“宽度的百分之一或高度的百分之一”。当 viewBox 是一个长方形(宽或高不相等),结果将根据上在的公式来计算。

注意,刚才提到给图标设置 stroke-width 可能会使得图标边缘被 viewBox 裁剪,除了在设计图标时考虑预留一定空间之外,还可以通过调整 viewBox 的值。这也再次彰显了 viewBox 在 SVG 中的重要性。

上面我们在讨论 CSS 如何样式化 SVG 图标时,它们都有一个前提条件,那就是 <symbol> 元素实例化图标时,该元素上没有设置与样式有关的任何属性,哪怕是“演示属性”。但我们在获取图标时,有些图标会自带“演示属性”,例如 fill 属性。此时,即使你在 CSS 中设置了 fill 属性,你也将无法覆盖 <symbol> 元素自带的样式。例如:

XML
<svg class="icon icon--flower">
    <use href="#flower" />
</svg>
 
<svg class="sr-only">
    <symbol id="flower" viewBox="0 0 1024 1024">
        <path d="M372.362 286.38h42.674v133.552h-42.674zM887.206 54.826h42.674v115.028h-42.674zM609.758 148.174h42.676v115.028h-42.676z" fill="#8CC153" />
        <path d="M888.706 304.906v71.354c0 11.778 9.56 21.338 21.338 21.338s21.336-9.56 21.336-21.338v-71.354h-42.674zM611.29 469.608a21.326 21.326 0 0 0 21.338 21.336c11.778 0 21.338-9.558 21.338-21.336v-71.384h-42.676v71.384zM373.862 554.958v71.382c0 11.778 9.56 21.338 21.336 21.338 11.808 0 21.336-9.56 21.336-21.338v-71.382h-42.672z" fill="#E6E9ED" />
        <path d="M1007.324 163.418c-12.402-14.244-30.272-21.804-51.704-21.804-21.054 0-35.77 11.464-45.828 24.554-10.248-13.058-25.086-24.554-46.08-24.554-20.776 0-38.894 7.748-51.016 21.774-13.872 16.028-19.15 38.394-15.308 64.73 3.56 24.338 16.026 49.142 35.084 69.822 20.21 21.962 46.266 37.084 73.382 42.52l4.218 0.876 4.216-0.876c27.116-5.466 53.202-20.556 73.448-42.488 19.18-20.742 31.614-45.61 35.02-69.978 4.658-33.334-5.808-53.516-15.432-64.576zM678.208 234.958c-21.056 0-35.77 11.466-45.83 24.554-10.248-13.056-25.086-24.554-46.112-24.554-20.742 0-38.864 7.748-51.016 21.776-13.84 16.026-19.12 38.394-15.278 64.7 3.562 24.368 15.996 49.172 35.052 69.854 20.244 21.96 46.298 37.05 73.416 42.518l4.186 0.844 4.216-0.844c27.148-5.466 53.234-20.556 73.478-42.486 19.15-20.776 31.584-45.612 35.022-70.01 4.652-33.302-5.812-53.484-15.434-64.542-12.4-14.248-30.302-21.81-51.7-21.81zM492.482 413.498c-12.402-14.276-30.272-21.804-51.704-21.804-21.056 0-35.74 11.464-45.83 24.554-10.248-13.058-25.086-24.554-46.08-24.554-20.776 0-38.894 7.748-51.016 21.774-13.838 15.996-19.12 38.394-15.276 64.7 3.53 24.37 15.996 49.142 35.052 69.854 20.212 21.962 46.298 37.052 73.384 42.52l4.218 0.844 4.218-0.844c27.116-5.466 53.234-20.556 73.478-42.488 19.15-20.774 31.584-45.61 34.99-70.01 4.684-33.336-5.812-53.486-15.434-64.546z" fill="#EC87C0" />
        <path d="M52.022 473.012c5 4.374 31.616 26.368 65.106 30.99 3.936 0.532 9.904 1.406 16.246 2.344 31.366 4.624 41.488 5.966 48.048 5.966 1.094 0 2.156-0.032 3.186-0.094h18.494l10.528-13.496c1.592-1.562 2.842-2.966 3.75-3.966 1.936-2.188 4.436-5.154 7.622-8.998 5.5-6.624 12.214-14.964 18.152-22.336 4.03-5 7.84-9.716 10.372-12.778 21.462-26.118 26.086-60.326 26.804-66.95l5.498-51.328-27.148 2.25c-1-5.342-1.938-8.936-2.25-9.998l-16.962-61.636-38.55 30.052-28.428-52.546-22.31 27.43c-5.312-5.436-9.186-8.778-10.278-9.714l-59.888-50.266-9.904 77.538c-0.188 1.438-0.782 6.56-1 14.184l-35.052-4.998 14.776 57.858L0.1 356.61l29.366 56.794c0.532 1 2.25 4.25 5.156 8.842l-21.494 16.776 38.894 33.99zM331.812 842.398l-27.368-28.928c11.966-8.154 19.494-14.87 21.182-16.4l57.608-52.89-75.634-19.87c-1.562-0.406-11.558-2.936-26.46-4.624l10.714-38.458-63.386 7.684c-0.906 0.094-2.968 0.376-5.966 0.844l2.624-56.7L164.988 654.8c-1.686 0.624-8.748 3.282-18.338 8.214l-15.496-26.272-38.738 34.146c-5.718 5.058-34.708 32.05-44.862 69.226-1.282 4.718-3.312 11.81-5.436 19.34-3.124 11.09-6.686 23.648-9.404 33.708a586.548 586.548 0 0 0-3.5 13.622c-0.406 1.812-0.968 4.188-1.374 7.03l-2.468 8.78 2.25 7.058 0.594 10.592 8.498 8.654c1.594 2.188 3.124 3.904 4.28 5.248 2.25 2.592 5.342 5.998 9.434 10.402 7.124 7.654 16.12 17.088 24.054 25.398 5.406 5.654 10.528 10.998 13.84 14.558 26.368 28.116 64.636 38.426 72.04 40.236l50.172 12.092 1.468-30.458c10.966-0.156 18.526-1.124 20.026-1.344l63.324-8.842-28.834-48.922c2.968-1 4.936-1.75 5.686-2.032l59.608-22.836z" fill="#8CC153" />
        <path d="M1023.882 21.494c0-11.808-9.558-21.338-21.338-21.338-1.03 0-2.06 0.094-3.06 0.218-2.5 0.344-62.136 9.186-152.36 35.832-83.102 24.526-208.75 69.45-335.462 144.3-142.988 84.444-258.14 188.91-342.27 310.498C64.05 643.242 7.566 822.5 1.444 1023.844h42.706c6.06-192.16 59.856-363.044 159.888-507.906 80.414-116.434 190.816-216.686 328.15-298.004 122.84-72.698 244.926-116.496 325.684-140.426 87.786-25.992 147.174-34.834 147.766-34.896v-0.032c10.31-1.498 18.244-10.372 18.244-21.086z" fill="#A0D468" />
    </symbol>
</svg>
CSS
.icon {
    display: block;
    width: 1em;
    aspect-ratio: var(--ratio, 1);
    fill: currentColor;
}
 
.icon--flower {
    color:yellow;
    font-size: 30vw;;
}

你会发现,.icon--flower 中的样式没法覆盖 <symbol><path> 元素的 fill 值。

这是因为 <use> 的后代元素都是 Shadow DOM,普通的 CSS 选择器是无法穿透 Shadow DOM。因此,我们需要人为去干涉,比如删除 <symbol> 后代元素(绘制图形相关元素)上的所有与样式有关的属性,包括演示属性。如果你的图标和上面示例所呈现的一样,是一个多色的图标,那么仅仅删除元素上的样式属性还是不够的。这个时候我们需要使用更高级的技术,使用 CSS 自定义属性来描述元素的样式属性的值。比如,上面的花,可以这样来修改:

XML
<svg class="sr-only">
    <symbol id="flower" viewBox="0 0 1024 1024">
        <path fill="var(--fill-color1,#8CC153)" d="M372.362 286.38h42.674v133.552h-42.674zM887.206 54.826h42.674v115.028h-42.674zM609.758 148.174h42.676v115.028h-42.676z"  />
        <path fill="var(--fill-color2, #E6E9ED)" d="M888.706 304.906v71.354c0 11.778 9.56 21.338 21.338 21.338s21.336-9.56 21.336-21.338v-71.354h-42.674zM611.29 469.608a21.326 21.326 0 0 0 21.338 21.336c11.778 0 21.338-9.558 21.338-21.336v-71.384h-42.676v71.384zM373.862 554.958v71.382c0 11.778 9.56 21.338 21.336 21.338 11.808 0 21.336-9.56 21.336-21.338v-71.382h-42.672z"  />
        <path fill="var(--fill-color3, #EC87C0)" d="M1007.324 163.418c-12.402-14.244-30.272-21.804-51.704-21.804-21.054 0-35.77 11.464-45.828 24.554-10.248-13.058-25.086-24.554-46.08-24.554-20.776 0-38.894 7.748-51.016 21.774-13.872 16.028-19.15 38.394-15.308 64.73 3.56 24.338 16.026 49.142 35.084 69.822 20.21 21.962 46.266 37.084 73.382 42.52l4.218 0.876 4.216-0.876c27.116-5.466 53.202-20.556 73.448-42.488 19.18-20.742 31.614-45.61 35.02-69.978 4.658-33.334-5.808-53.516-15.432-64.576zM678.208 234.958c-21.056 0-35.77 11.466-45.83 24.554-10.248-13.056-25.086-24.554-46.112-24.554-20.742 0-38.864 7.748-51.016 21.776-13.84 16.026-19.12 38.394-15.278 64.7 3.562 24.368 15.996 49.172 35.052 69.854 20.244 21.96 46.298 37.05 73.416 42.518l4.186 0.844 4.216-0.844c27.148-5.466 53.234-20.556 73.478-42.486 19.15-20.776 31.584-45.612 35.022-70.01 4.652-33.302-5.812-53.484-15.434-64.542-12.4-14.248-30.302-21.81-51.7-21.81zM492.482 413.498c-12.402-14.276-30.272-21.804-51.704-21.804-21.056 0-35.74 11.464-45.83 24.554-10.248-13.058-25.086-24.554-46.08-24.554-20.776 0-38.894 7.748-51.016 21.774-13.838 15.996-19.12 38.394-15.276 64.7 3.53 24.37 15.996 49.142 35.052 69.854 20.212 21.962 46.298 37.052 73.384 42.52l4.218 0.844 4.218-0.844c27.116-5.466 53.234-20.556 73.478-42.488 19.15-20.774 31.584-45.61 34.99-70.01 4.684-33.336-5.812-53.486-15.434-64.546z"  />
        <path fill="var(--fill-color1,#8CC153)" d="M52.022 473.012c5 4.374 31.616 26.368 65.106 30.99 3.936 0.532 9.904 1.406 16.246 2.344 31.366 4.624 41.488 5.966 48.048 5.966 1.094 0 2.156-0.032 3.186-0.094h18.494l10.528-13.496c1.592-1.562 2.842-2.966 3.75-3.966 1.936-2.188 4.436-5.154 7.622-8.998 5.5-6.624 12.214-14.964 18.152-22.336 4.03-5 7.84-9.716 10.372-12.778 21.462-26.118 26.086-60.326 26.804-66.95l5.498-51.328-27.148 2.25c-1-5.342-1.938-8.936-2.25-9.998l-16.962-61.636-38.55 30.052-28.428-52.546-22.31 27.43c-5.312-5.436-9.186-8.778-10.278-9.714l-59.888-50.266-9.904 77.538c-0.188 1.438-0.782 6.56-1 14.184l-35.052-4.998 14.776 57.858L0.1 356.61l29.366 56.794c0.532 1 2.25 4.25 5.156 8.842l-21.494 16.776 38.894 33.99zM331.812 842.398l-27.368-28.928c11.966-8.154 19.494-14.87 21.182-16.4l57.608-52.89-75.634-19.87c-1.562-0.406-11.558-2.936-26.46-4.624l10.714-38.458-63.386 7.684c-0.906 0.094-2.968 0.376-5.966 0.844l2.624-56.7L164.988 654.8c-1.686 0.624-8.748 3.282-18.338 8.214l-15.496-26.272-38.738 34.146c-5.718 5.058-34.708 32.05-44.862 69.226-1.282 4.718-3.312 11.81-5.436 19.34-3.124 11.09-6.686 23.648-9.404 33.708a586.548 586.548 0 0 0-3.5 13.622c-0.406 1.812-0.968 4.188-1.374 7.03l-2.468 8.78 2.25 7.058 0.594 10.592 8.498 8.654c1.594 2.188 3.124 3.904 4.28 5.248 2.25 2.592 5.342 5.998 9.434 10.402 7.124 7.654 16.12 17.088 24.054 25.398 5.406 5.654 10.528 10.998 13.84 14.558 26.368 28.116 64.636 38.426 72.04 40.236l50.172 12.092 1.468-30.458c10.966-0.156 18.526-1.124 20.026-1.344l63.324-8.842-28.834-48.922c2.968-1 4.936-1.75 5.686-2.032l59.608-22.836z"  />
        <path fill="var(--fill-color4, #A0D468)" d="M1023.882 21.494c0-11.808-9.558-21.338-21.338-21.338-1.03 0-2.06 0.094-3.06 0.218-2.5 0.344-62.136 9.186-152.36 35.832-83.102 24.526-208.75 69.45-335.462 144.3-142.988 84.444-258.14 188.91-342.27 310.498C64.05 643.242 7.566 822.5 1.444 1023.844h42.706c6.06-192.16 59.856-363.044 159.888-507.906 80.414-116.434 190.816-216.686 328.15-298.004 122.84-72.698 244.926-116.496 325.684-140.426 87.786-25.992 147.174-34.834 147.766-34.896v-0.032c10.31-1.498 18.244-10.372 18.244-21.086z"  />
    </symbol>
</svg>

这个时候,你只需要在 CSS 改变自定义属性的值即可:

CSS
.icon--flower {
    --fill-color1: red;
    --fill-color2: orange;
    --fill-color3: yellow;
    --fill-color4: lime;
}

Demo 地址:https://codepen.io/airen/full/zYXPGvw

另外,除了纯色填充之外,还可以是渐变色和纹理等:

Demo 地址:https://codepen.io/airen/full/LYvLNjw

有关这方面更详细的介绍,我们会在后续的课程中与大家一起探讨!

小结

现在,你已经掌握了使用 SVG 创建自己的图标系统的所有环节。从设计图标(或获取图标)到创建雪碧图,再到将图标集成到 Web 应用或网站上,最后样式化图标。除此之外,你还掌握了自动化创建图标系统的方法。在后续的实战课中,我们还将进一步探讨,你创建的图标系统在各个技术框架中如何使用。