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

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

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

  1. <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">
  2. <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>
  3. </svg>

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

  1. <svg>
  2. <symbol viewBox="0 0 24 24" id="heart">
  3. <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>
  4. </symbol>
  5. </svg>

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

  1. <body>
  2. <svg style="display: none;">
  3. <symbol viewBox="0 0 24 24" id="heart">
  4. <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>
  5. </symbol>
  6. </svg>
  7. <svg>
  8. <use xlink:href="#heart"/> <!-- this is our visible icon -->
  9. </svg>
  10. </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>元素来包裹。

  1. <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  2. <symbol viewBox="0 0 24 24" id="heart">
  3. <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>
  4. </symbol>
  5. <symbol viewBox="0 0 32 32" id="arrow">
  6. <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>
  7. </symbol>
  8. </svg>

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

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

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

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

  1. <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  2. <symbol viewBox="0 0 24 24" id="heart">
  3. <title>Heart</title>
  4. <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>
  5. </symbol>
  6. <symbol viewBox="0 0 32 32" id="arrow">
  7. <title>Arrow</title>
  8. <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>
  9. </symbol>
  10. </svg>

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

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

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

就这样,so easy!

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

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

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

  1. <svg style="display: none;"> <!-- this is our svg sprite -->
  2. <symbol viewBox="0 0 24 24" id="heart">
  3. <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>
  4. </symbol>
  5. <symbol viewBox="0 0 32 32" id="arrow">
  6. <!-- ... -->
  7. </symbol>
  8. </svg>
  9. <svg>
  10. <use xlink:href="#heart"/> <!-- this is our visible icon -->
  11. </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选择器并不能获取到,所以假设我们有如下的图标:

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

然后这样添加样式:

  1. .icon path {
  2. fill: #000000;
  3. }

是没有办法工作的。

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

  1. <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  2. <symbol viewBox="0 0 24 24" id="heart">
  3. <title>Heart</title>
  4. <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>
  5. </symbol>
  6. <symbol viewBox="0 0 32 32" id="arrow">
  7. <title>Arrow</title>
  8. <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>
  9. </symbol>
  10. </svg>

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

  1. <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  2. <symbol viewBox="0 0 24 24" id="heart">
  3. <title>Heart</title>
  4. <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>
  5. </symbol>
  6. <symbol viewBox="0 0 32 32" id="arrow">
  7. <title>Arrow</title>
  8. <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>
  9. </symbol>
  10. </svg>

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

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

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

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

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

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

  1. .my-class-name {
  2. fill: red;
  3. }

使用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

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

然后在CSS中修改:

  1. .my-class-name {
  2. color: purple;
  3. }

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

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

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. cocos2dx重新设置 SDK NDK目录

    参考博客https://blog.csdn.net/yinhe888675/article/details/41042347 初始设置SDK,NDK目录后,当我想换目录的时候不知道该怎么办,怎么重新设 ...

  2. HahMap(jdk=1.8)源码解读

    简介:岁月磨平了人的棱角,让我们不敢轻易的去放手,即使它在你心中并不那么重要,你依旧害怕失去它,不是舍不得,是内心的迷茫. 一 : 创建HashMap HashMap<Object, Objec ...

  3. HashMap 21问!!

    1:HashMap的数据结构? A:哈希表结构(链表散列:数组+链表)实现,结合数组和链表的优点.当链表长度超过8时,链表转换为红黑树. transient Node<K,V>\[\] t ...

  4. Wireshark中遇到的epoch time

    使用Wireshark分析DNS时遇到的Epoch time 首先看一下Wireshark分析DNS的情况(如下图): 这是协议树的第一项,第一项中的第五行出现了Epoch Time,查阅资料之后才知 ...

  5. 算法-排序(1)k路平衡归并与败者树

    const int MaxValue=; //根据实际情况选择最大值 void kwaymerge(Element *r,int k){ int i,q; r=new Element[k]; //在败 ...

  6. 【转】Windows10删除文件时却提示文件不存在的解决方案

    Windows10系统使用一段时间后用户都会定期进行删除清理系统垃圾,减少系统盘的容量占用,但在删除的过程中许多用户都有可能遇到无法删除的情况,如下为删除文件时却提示文件不存在的解决方案. 1.新建一 ...

  7. 吊打 Tomcat ,Undertow 性能很炸!!

    在 Java Web 容器的世界里,Tomcat 和 Jetty 是大名鼎鼎的.用的最多的开源项目,也是大众熟知的. 今天再介绍另外一款能和 Tomcat 媲美的神器:Undertow,据说性能方面还 ...

  8. Nuxt.js 踩坑记录(3) Net.connection xxxx

    浏览器报的是Net.connection啥的错误 项目运行时报错这个 [HPM] Error occurred while trying to proxy request article from l ...

  9. Lambda 表达式推演全过程

    Java 的 Lambda 表达式推演过程: 第一步:正常的类实现(外部实现),new一个对象,然后重写方法实现 public class TestLambda3 { public static vo ...

  10. MapReduce 的 shuffle 过程中经历了几次 sort ?

    shuffle 是从map产生输出到reduce的消化输入的整个过程. 排序贯穿于Map任务和Reduce任务,是MapReduce非常重要的一环,排序操作属于MapReduce计算框架的默认行为,不 ...