在实现Web项目的图标系统时,SVG是一个不错的选择。虽然使用SVG创建图标系统有多种方式。在这篇文章中,我们只看其中一种:SVG symbols。这项技术基于两个元素的使用:<symbol><use>

<symbol>元素用来对元素进行分组;它不会被直接显示,大概相当于定义一个模板,然后使用<use>元素引用并进行渲染。

我们使用Illustrator创建并导出SVG图标:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24">
<path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
</svg>

然后将内容包裹在<symbol>元素中:

<svg>
<symbol viewBox="0 0 24 24" id="heart">
<path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
</symbol>
</svg>

现在如果我们把这段代码插入到我们的页面中,我们会看到图标并不显示,因为要显示图标,我们还需要使用<use>元素:

<body>
<svg style="display: none;">
<symbol viewBox="0 0 24 24" id="heart">
<path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
</symbol>
</svg> <svg>
<use xlink:href="#heart"/> <!-- this is our visible icon -->
</svg>
</body>

结果如下:

换句话说,就是你定义了一组图形对象(使用<symbol>元素)之后,可以使用<use>元素来对它进行无限次实例化展示。你使用xlink:href属性来指定你想要展示哪一组图标,这里,我们要展示的是id#heart<symbol>元素。

你可能注意到了我们给包裹<symbol>元素的SVG标签加了一个style="display: none;"的样式:这是因为即使<symbol>本身没有显示,但是包裹它的<svg>元素依旧会渲染并占用一些页面空间,这就是为什么我们需要隐藏svg元素。

现在我们知道了<symbol><use>元素分别是什么,以及它们是如何工作的,我们可以来建立我们的SVG sprite了。

首先,你需要准备好所有图标,每个图标放一个单独的.svg文件。然后再创建一个新的(空白的).svg文件(我把它命名为myicons.svg)。

在这个新的svg文件中,插入一个<svg>标签,然后,对于每一个你要放进去的图标,分别用一个<symbol>元素来包裹。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol viewBox="0 0 24 24" id="heart">
<path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
</symbol> <symbol viewBox="0 0 32 32" id="arrow">
<path fill="#0f0f0f" d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16s16-7.2,16-16S24.8,0,16,0z M22.8,13.6l-6,8C16.6,21.9,16.3,22,16,22 s-0.6-0.1-0.8-0.4l-6-8c-0.2-0.3-0.3-0.7-0.1-1S9.6,12,10,12h12c0.4,0,0.7,0.2,0.9,0.6S23,13.3,22.8,13.6z"></path>
</symbol>
</svg>

每个<symbol>元素都设置一个id,这个id用来在后面使用<use>的时候引用。

我们还给每个<symbol>元素指定了一个viewBox属性。这个viewBox属性定义了图标的宽高比;它包含4个值,前面2个值通常为0(但它其实是依赖于图标是如何绘制的),另外两个值分别是SVG的宽和高(如果你对于viewBox属性不熟悉,可以看看这篇关于SVG缩放的文章)。

这样你的图标不需要保持相同的宽高比,因为你可以给每个图标分别定义不同的viewBox属性。

最后一步,我们可以给每个图标添加一个<title>标签,提升它的可访问性。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol viewBox="0 0 24 24" id="heart">
<title>Heart</title>
<path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
</symbol> <symbol viewBox="0 0 32 32" id="arrow">
<title>Arrow</title>
<path fill="#0f0f0f" d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16s16-7.2,16-16S24.8,0,16,0z M22.8,13.6l-6,8C16.6,21.9,16.3,22,16,22 s-0.6-0.1-0.8-0.4l-6-8c-0.2-0.3-0.3-0.7-0.1-1S9.6,12,10,12h12c0.4,0,0.7,0.2,0.9,0.6S23,13.3,22.8,13.6z"></path>
</symbol>
</svg>

我们的SVG sprite现在可以投入使用了。你可以保存文件为myicons.svg,放在资源文件夹中(我通常把这个文件夹明明为img)。

接下来展示我们的图标,你需要做的就是在文档中你想要放置图标的位置插入下面这一小段:

<svg>
<use xlink:href="img/myicons.svg#heart"/>
</svg>

就这样,so easy!

浏览器兼容性如何呢?在IE中通过<use>引用外部SVG文件的方法是不可行的,IE9以上也不行(不过,这个问题在Edge中已经解决了)。

那要如何解决呢?我们来看看两种可能的解决方案。

我们可以在文档的顶部引入SVG sprite,然后使用<use>标签引用图标:

<svg style="display: none;"> <!-- this is our svg sprite -->
<symbol viewBox="0 0 24 24" id="heart">
<path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
</symbol> <symbol viewBox="0 0 32 32" id="arrow">
<!-- ... -->
</symbol>
</svg> <svg>
<use xlink:href="#heart"/> <!-- this is our visible icon -->
</svg>

注意xlink:href属性和id标识符是唯一对应的(它不能引用外部资源中的id)。

这种方法非常好用,但缺点是SVG sprite不能缓存。

我们可以使用一个polyfill;举个例子,svgxuse。这个polyfill可以根据<use>元素的引用,获取外部SVG资源中的id,而浏览器本身并不能这样做。基本远离就是,这个polyfill遍历文档中的<use>元素,然后如果它引用的是浏览器无法加载的外部SVG文件,它就在外部SVG中抓取并预置到文档中的<body>中。good!

你可以在Github repo中下载这个polyfill,在文档中引入,就ok了。

注意:SVG只在IE9以上支持;所以如果你需要支持IE8及以下的浏览器,你需要另外再写一套降级(例如,使用png图片方案)。

接下来,怎么给SVG添加样式呢?给SVG <use>元素添加样式需要一点技巧。这是因为SVG 图标引用这种方式有自己单独的DOM结构(也就是shadow DOM),CSS选择器并不能获取到,所以假设我们有如下的图标:

<svg class="icon">
<use xlink:href="img/myicons.svg#heart"/>
</svg>

然后这样添加样式:

.icon path {
fill: #000000;
}

是没有办法工作的。

如何解决这个问题呢?比如说你想要改变图标的填充颜色。首先,确保fill属性不是svg文件中内联定义的。所以,如果图标 sprite如下:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol viewBox="0 0 24 24" id="heart">
<title>Heart</title>
<path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
</symbol> <symbol viewBox="0 0 32 32" id="arrow">
<title>Arrow</title>
<path fill="#0f0f0f" d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16s16-7.2,16-16S24.8,0,16,0z M22.8,13.6l-6,8C16.6,21.9,16.3,22,16,22 s-0.6-0.1-0.8-0.4l-6-8c-0.2-0.3-0.3-0.7-0.1-1S9.6,12,10,12h12c0.4,0,0.7,0.2,0.9,0.6S23,13.3,22.8,13.6z"></path>
</symbol>
</svg>

把内联fill属性删除,如下:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol viewBox="0 0 24 24" id="heart">
<title>Heart</title>
<path d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
</symbol> <symbol viewBox="0 0 32 32" id="arrow">
<title>Arrow</title>
<path d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16s16-7.2,16-16S24.8,0,16,0z M22.8,13.6l-6,8C16.6,21.9,16.3,22,16,22 s-0.6-0.1-0.8-0.4l-6-8c-0.2-0.3-0.3-0.7-0.1-1S9.6,12,10,12h12c0.4,0,0.7,0.2,0.9,0.6S23,13.3,22.8,13.6z"></path>
</symbol>
</svg>

然后在你的css代码中,加入:

.icon {
fill: #00000; /* this will be your icons default color */
}

因为你没有在SVG中给path元素指定fill,所以它们会继承父级元素,即SVG的fill属性,这样你可以直接使用CSS选择器修改这个属性。

现在,如果我们只想改变一个图标的fill,怎么办呢?我们给这个图标再单独指定一个class即可:

<svg class="icon my-class-name">
<use xlink:href="img/myicons.svg#heart"></use>
<svg>

然后使用CSS改变它的fill值:

.my-class-name {
fill: red;
}

使用Nucleo创建SVG symbol sprite

手动创建一个SVG symbol sprite是非常麻烦的,特别是如果你有相对多的图标。Nucleo自动化SVG symbol sprites构建工具可以帮助你省下很多琐碎活。

从Nucleo的网站上,选择你想要下载图标,然后点击下载按钮。在弹出的设置窗口中,勾上‘Export as <symbol>选项,然后填写你的资源文件夹的路径(这里会为<use>元素设置一个xlink:href值);填写一个文件名(这是你的SVG sprite文件的名字)。然后点击保存。完成啦!你的sprite就可以用了。

你下载的文件夹中会包含几样东西:

  • 你的SVG sprite;
  • 一个style.css文件(在css文件夹中):它包含基本的SVG样式(例如,你在app中设置的fill/stroke属性);你需要复制这块内容到你的样式文件中(或者作为一个额外的css文件引入);
  • 一个svgxuse.min.js文件(在js文件夹中),这是针对IE9+的polyfill;你需要在你的文档中引入这个文件,如果你希望图标在IE9+的浏览器中可以正确显示的话;
  • 最后,一个demo.html文件。

基本上,这个demo文件列出了所有你下载的图标,你可以直接在你的文档中引入它们:点击你想要引入的图标,它就会选中你需要复制的代码片段,然后在你的文档中粘贴即可。

图标也会按照你在Nucleo app中设置的样式显示。

怎么给单个图标添加样式呢?你可以给图标指定一个class

<svg class="nc-icon grid-32 glyph my-class-name">
<use xlink:href="img/myicons.svg#double-left"/>
</svg>

然后在CSS中修改:

.my-class-name {
color: purple;
}

OK。但是,Nucleo图标是双色的....如果我想改变的是其中的第二种颜色的?这也好办,加上:

.my-class-name use {
color: orange;
}

OK啦。

我们的symbols有一些额外的技巧。

  • 我们的内联图标有可定制的stroke。如果你想要改变某个图标的stroke-width属性呢?假设你下载的图标stroke-width2px,那么stroke-2类会自动添加到SVG元素上。如果你想要把stroke切换为3px,只需要把stroke-2类改为stroke-3类就可以啦。
  • 那如何让图标和文本对齐呢?在demo文件中,在顶部,可以选择‘align to text’;然后复制SVG片段并粘贴到你的文档中(感谢Cloud Four提供的'align to text'样式)。 注意,在这里,SVG会继承文本的颜色;但是,你同样可以使用一个自定义类,给它添加自定义样式,和前面一样。
  • 如果你更倾向于在文档中引入SVG sprite(而不是作为一个外部的SVG文件引用),不要勾选'Reference external SVG'选项(在demo文件的顶部);这会自动将xlink;href属性设置为和<symbol>的唯一标识符id相等的名字。

使用SVG symbols真的是管理图标的非常智能的方法;这是为什么我们在Nucleo中加入了'symbol export'功能。

使用Nucleo管理图标也是非常方便的,即使你手头有多个项目:你需要做的只是创建一个项目,添加你需要的图标,然后点击几下,下载即可。

本文根据@Claudia Romano的《How to create an icon system using SVG symbols》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://nucleoapp.com/how-to-create-an-icon-system-using-svg-symbols/

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
原文: http://www.w3cplus.com/svg/how-to-create-an-icon-system-using-svg-symbols.html © w3cplus.com

使用SVG symbols建立图标系统的更多相关文章

  1. 使用SVG symbols建立图标系统完整指南

    从最开始的使用img图片,到后来的使用css sprite来减少服务器请求,再到流行的图形字体化图标Iconfont.现在,一种全新的图标使用方式开始流行了起来--SVG symbols图标. 工作原 ...

  2. Windows重新建立图标缓存

    有的时候,快捷方式的图标会因各种优化软件而变得面目全非,这时就需要重新建立图标缓存 新建一个文本文档,把文件的后缀名修改成.bat 的例如 icon.bat 在里面填写下面的内容: rem 关闭exp ...

  3. XE下 SVG格式的图标使用方法

    下载一个SVG格式的图标,千图网,http://tool.58pic.com/tubiaobao/ 用txt文本打开SVG图标 拖一个PathLabel控件 在PathLabel控件的Data属性添加 ...

  4. Fedora10下建立linux系统的窗口没有地址栏

    Fedora10下建立的linux系统窗口没有地址栏 打开一个文件夹就打开一个窗口,还没有地址栏,这很麻烦也不习惯. 另:打开地址栏可以用组合键 Ctrl+L 如图 解决: edit---perfer ...

  5. SVG 和字符图标

    制作网站往往需要使用一些图标来提高用户体验,如果我们的是一些扁平化设计的图标,我们可以选择 SVG 或 图标字体来提高用户体验. 下面对这两种技术进行比较. 开发难度: 现在的在线工具非常强大,比如  ...

  6. svg图片做图标字体

    https://icomoon.io 这个网站,把svg变图标

  7. 基于开源软件在Azure平台建立大规模系统的最佳实践

    作者 王枫 发布于2014年5月28日 前言 Microsoft Azure 是微软公有云的唯一解决方案.借助这一平台,用户可以以多种方式部署和发布自己的应用. 这是一个开放的平台,除了对于Windo ...

  8. 克隆虚拟机系统整个文件快照,然后另起建立该系统,产生的IP地址冲突解决办法

    进入克隆后的文件系统 cd /etc/sysconfig/network-scripts/ cp ifcfg-eth0  ifcfg-eth1 vim ifcfg-eth1   #修改其中的文件内容 ...

  9. SVG生成字体图标详解

随机推荐

  1. MyBatis使用LocalDateTime遇到的一系列问题

    问题 在Mybaits中传入参数为LocalDateTime,查询发现结果集为空,插入时发现时间相差13小时 测试 新建工程,新建测试库(主要此处新工程使用的JDBC为mysql-connector- ...

  2. Java爬取先知论坛文章

    Java爬取先知论坛文章 0x00 前言 上篇文章写了部分爬虫代码,这里给出一个完整的爬取先知论坛文章代码. 0x01 代码实现 pom.xml加入依赖: <dependencies> & ...

  3. vue跳转页面问题记录

    跳转到别的页面带参数 const space = this.pageHelperspace['search'] = this.searchconst query_params = Object.ass ...

  4. 程序流程结构——if语句

    c语言支持最基本的三种运行结构: 顺序结构:程序按顺序执行,不发生跳转 选择结构:根据是否满足条件 ,有选择的执行相应功能 循环结构:依据条件是否满足,循环多次执行某段代码 #define _CRT_ ...

  5. 一文看懂 Netty 架构设计

    本文重点分析 Netty 的逻辑架构及关键的架构质量属性,希望有助于大家从 Netty 的架构设计中汲取营养,设计出高性能.高可靠性和可扩展的程序. Netty 的三层架构设计 Netty 采用了典型 ...

  6. Kerberos认证原理及基于Kerberos认证的NFS文件共享

    目录 Kerberos认证原理 简介 client访问server过程 一.Authentication Service Exchange (AS Exchange) 二.Ticket Grantin ...

  7. Spark优化之小文件是否需要合并?

    我们知道,大部分Spark计算都是在内存中完成的,所以Spark的瓶颈一般来自于集群(standalone, yarn, mesos, k8s)的资源紧张,CPU,网络带宽,内存.Spark的性能,想 ...

  8. ubuntu开发机所需工具,做个记录,不断补充

    文件搜索 FSearch 用了下可以, 类似windows下的Everything 或者mac的cmd+空格 地址 安装: sudo add-apt-repository ppa:christian- ...

  9. 第一章 Kubernetes入门

    第一章 Kubernetes入门 kubernetes是基于容器技术的分布式架构领先方案,是一个完备的分布式系统支撑平台. kubernetes带来的好处:1)全面拥抱微服务:2)统可以随时随地整体“ ...

  10. mysql表中已有数据,为表新增一个自增id。

    第一步,在navicat中,例如表test新建查询,输入以下两行代码即可搞定. alter table test add id int; alter table `test` change id id ...