zoukankan      html  css  js  c++  java
  • SVG Sprite技术介绍

    未来必热:SVG Sprite技术介绍

    一、Sprite技术

    这里所说的Sprite技术,没错,类似于CSS中的Sprite技术。图标图形整合在一起,实际呈现的时候准确显示特定图标。

    另,本文图片甚多,爪机党继续浏览需慎重。

    二、SVG Sprite与symbol元素

    目前,SVG Sprite最佳实践是使用symbol元素。symbol元素是什么呢?单纯翻译的话,是“符号”的意思。然,这个释义并不符合这里的场景。不知大家有没有用过Flash,symbol实际上就类似于Flash中的“影片剪辑”、或者“元件”。

    因此,我个人觉得,symbol应该解释为“元件”最为恰当!

    那,symbol和SVG Sprite又有什么关系呢?

    我们可以把SVG元素看成一个舞台,而symbol则是舞台上一个一个组装好的元件,这这些一个一个的元件就是我们即将使用的一个一个SVG图标。

    于是,对于一个集合了三个SVG图标的SVG元素的代码结构会是这样:

    <svg>
        <symbol>
            <!-- 第1个图标路径形状之类代码 -->
        </symbol>
        <symbol>
            <!-- 第2个图标路径形状之类代码 -->
        </symbol>
        <symbol>
            <!-- 第3个图标路径形状之类代码 -->
        </symbol>
    </svg>
    

    每一个symbol就是一个图标元件,但是,只有上面的代码,是无法呈现类似下面的效果的:
    SVG Sprite的效果图

    为何?

    因为,舞台上只是放置了图标,如果你不使用(use),是看不见的。就好比你女朋友买了几箱的衣服放家里,如果不穿出去,谁知道她这么土豪呢?

    因此,还差一个“使用”,也就是SVG中的<use>元素。

    三、SVG中的use元素

    use元素是SVG中非常强大,非常重要的一个元素,尤其在Web开发中,为何?

    两点:

    1. 可重复调用;
    2. 跨SVG调用;

    1. 可重复调用
    你好不容易,用了几十个坐标值,好不容易绘制了一个图形,如果你想再弄一个同样造型,但位置不同的图形出来,你会怎么办?——再复制一遍代码?别说笑了,(如果真那样)SVG文件的尺寸赶得上二师兄的腰围了。

    使用<use>元素就可以,看下面的板栗:

    <svg>
      <defs>
        <g id="shape">
            <rect x="0" y="0" width="50" height="50" />
            <circle cx="0" cy="0" r="50" />
        </g>
      </defs>
    
      <use xlink:href="#shape" x="50" y="50" />
      <use xlink:href="#shape" x="200" y="50" />
    </svg>

    结果是(IE9+浏览器可见):

    首先,注意到没有,use元素是通过xlink:href属性,寻找要使用的元素的。#shape对应的就是idshape的元素。use元素可以有自己的坐标,以及支持transform变换,甚至可以use其他use元素。

    这里,两个use元素使用的是同一个g元素(组合),从而实现了图形的重复调用功能。

    2. 跨SVG调用
    SVG中的use元素可以调用其他SVG文件的元素,只要在一个文档中。

    紧接着上面的板栗:

    <svg width="500" height="110"><use xlink:href="#shape" x="50" y="50" /></svg>

    结果仍是那个图形:

    而这个跨SVG调用就是“SVG Sprite技术”的核心所在。

    试想下,我们只要在页面某处载入一个充满Sprite(symbol)的SVG文件(或直接include SVG代码),于是,在页面的任何角落,只要想使用这个图标,只要简单这一点代码就可以了:

    <svg class="size"><use xlink:href="#target" /></svg>

    图标尺寸CSS控制,里面只有一个仅有xlink:href属性的use元素,Done! 完成!

    也即是说,在HTML层面,图标使用的代码成本,跟传统的CSS Sprite或者流行的font-face几乎无异,代码简洁,而且很好维护。所有的SVG图标都在一个SVG源上。retina良好,尺寸可任意拉伸,且颜色可控,真乃Web图标的未来之星。

    吹的嘴巴都干了,上个简单的demo给大家瞅瞅, 我先去给水排水~~

    您可以狠狠地点击这里:SVG Sprite使用示意demo

    代码如下截图:
    SVG Sprite使用示意

    效果为:
    SVG使用的图标效果

    总结下就是:symbol + use => SVG Sprite

    诸位会不会觉得本文的内容快要结束了呢?

    嘻嘻嘻嘻,顶多才1/3,下面的才是重点,打起精神,走起~~

    四、SVG Sprite实际应用的阻碍

    两大问题:

    1. SVG图标从何而来?
    2. SVG图标如何变成symbol并整合在一起?

    1个问题,SVG图标从何而来?
    “远在天边近在眼前”,CSS3 font-face的逐渐升温,让很多font-face工具诞生了。例如以前我介绍过的国外的icomoon.io,或者国内阿里系的iconfont.cn, 或者bootsrap 3粉们的font-awesome

    这些图标实际上都是使用SVG作为媒介的,所以,根本就不要担心“SVG图标从何而来”,这图标多的就像牛魔王身上的虱子——一抖一大把啊!

    OK,如何获得呢?直接下载。拿iconfont.cn示意,点击某一图标的下载按钮:
    点击下载图标

    点击下载SVG:
    点击下载SVG按钮

    于是,我们就得到了SVG图标啦!如果你还需要其他图标,也按照这个步骤一个一个下载下来,很简单吧~ 然后把它们放在一个文件夹中,以备后用。

    下面最关键的是第2个问题,如何合并这些SVG到一个SVG上?同时满足使用的是symbol标签,并可以使用裸露的use元素(除了xlink:href没有其他属性)调用呢?

    很长很funny, 要专门独立两段,

    五、关于合并:偏开发的前端看这里

    这里的方法适用于偏开发的前端,一些对指令无感的妹子们,可以看下面偏设计的方法。

    Github上,有个名为svgstoregrunt插件,地址戳这里。如果您还不了解grunt, 可以看看这两篇我觉得不错的文章:“使用GruntJS构建Web程序 (1)”和“使用GruntJS构建Web程序 (2)”.

    grunt改装的装好后,执行下面的指令,

    npm install grunt-svgstore --save-dev

    安装grunt-svgstore

    烧个香保佑安装成功,然后你就会看到在node_modules文件夹中一个名为grunt-svgstore的子文件夹(如下):
    grunt-svgstore文件夹

    这个名为grunt-svgstore的文件夹中有个名为Gruntfile.js的文件,据我个人理解,这个JS是所有grunt插件要使用的配置文件。

    我在里面做了一件事情,加了这么一行代码:
    加了一行代码示意

    为什么要加这么行代码呢?因为grunt-svgstore项目README.md让加的,所以我就加了 

    你会看到

    svgstore: {
    
    }

    中有一大堆的配置什么的,这些都是用来独立测试各个API的(options对象中各个键就是API名称),让你知道此插件各个API都是干嘛用的,具体释义参见该Github项目。忍不住提一下,如果你希望SVG图标颜色可以在CSS中通过fill控制,cleanup设置为true.

    OK, 准备工作完毕,下面来实践下。我把从iconfont.cn上下载下来的3个SVG都放在了一个名为mytest的文件夹下,我希望这个文件夹下的SVG都整合在一起,并可以方便调用,怎么办?

    svgstore: {}内部搞个自定义的配置,见下图:
    自定义的配置

    意思是:mytest文件夹下的所有SVG合并成一个名为mytest.svg的大SVG文件,并放在tmp文件夹下。

    我们cdgrunt-svgstore目录,然后在命令行工具中输入:

    grunt

    然后走起,再烧第2根香,保佑一切正常……
    mytest走起~

    然后,就可以在tmp文件夹下看到我们的小结晶——mytest.svg,以及如何使用示意的HTML demo页面。
    SVG合并的文件,以及对应的demo~

    此demo页面源代码如下:

    <svg xmlns="http://www.w3.org/2000/svg" style="0;height:0;visibility:hidden;"><symbol viewBox="0 0 1024 1024" id="iconfont-baobei"><title>iconfont-baobei</title><path fill="#272636" d="M...z" transform="translate(0, 800) scale(1, -1)"/></symbol><symbol viewBox="0 0 1024 1024" id="iconfont-bianji"><title>iconfont-bianji</title><path fill="#272636" d="M...z" transform="translate(0, 800) scale(1, -1)"/></symbol><symbol viewBox="0 0 1024 1024" id="iconfont-shangchuan"><title>iconfont-shangchuan</title><path fill="#272636" d="M...z" transform="translate(0, 800) scale(1, -1)"/></symbol></svg>
    
    <svg>
        <use xlink:href="#iconfont-baobei"></use>
    </svg>
    <svg>
        <use xlink:href="#iconfont-bianji"></use>
    </svg>
    <svg>
        <use xlink:href="#iconfont-shangchuan"></use>
    </svg>

    效果如下截图:
    第一次成型的SVG效果图

    Oh, no! 怎么有残缺,不完美,感觉不会再爱了!

    淡定,小问题,貌似是这些SVG制作的时候,本身有些问题(为了font-face做的调整?),我们在illustrator中打开这些SVG, 一下子就可以看出症结所在,例如,细细的铅笔图标:
    铅笔的两个角在舞台之外了

    铅笔的两个角在白色的舞台之外了,正好跟上面截图少掉的两个角一致。要修复,超easy, 等比例缩放到白色舞台内就OK了,ctrl+S保存,然后重新执行下grunt命令就好了。

    然后,浏览器刷新下刚刚的demo页面,当当当当,撒花撒花~~

    溢出调整后的SVG效果

    以上~

    六、关于合并:偏设计的前端看这里

    注意:这里的方法,就算是CSS完全不懂的设计师也可以轻松上手!

    对于一些妹子,只会写些页面,对于开发、编程的感觉比减肥还难,显然,上面的偏开发需编译的工具插件对她们就很吃力。不急不急,这里有面向设计师的方法。

    你需要一个犀利的软件,矢量之王,illustrator!

    一步一步跟我来:

    1. 打开软件,新建一个文件,然后另存为SVG格式;
    2. 从标尺中拉出一些参考线,搞些正方形格子,我自己用的尺寸是160*160, 矢量无尺寸,你随意;
    3. 把下载的SVG图形拖到这些格子中,缩放到合适大小。我是铺满的,这样由于对比明显,各个图标尺寸就都是一致的,CSS控制方便;
      illustrator参考线与图形缩放
    4. 这一步很关键。打开Symbols面板,在Window菜单栏中,或Shift+Ctrl+F11启用。然后,拖动格子中的SVG图形到这个面板中,就会触发新建“元件”的行为,会打开类似下面的面板:
      illustrator中新建元件的面板

      其中,name就是SVG中对应的symbol元素的id,因此,最好使用英文,最好易识别。下面的type你随意,这个只要在SVG导入到Flash中使用时候才有用的,这里,我们不和Flash打交道。然后,OK, 这个图标就“元件”化了,按照同样的步骤,让3个图标都变成元件(以后可重复使用),Symbols面板会类似下面这样:
      Symbols面板截图

    5. Ctrl+S保存,合并好的SVG即出炉。我们直接在浏览器中打开此SVG,效果不错哦~
      SVG Sprite的效果图

    是不是就这么结束了,太天真了。人生不如意事十之八九。我们瞅一瞅SVG的源代码,会发现,use元素居然跟小龙女一样,不干净纯洁啦——上面一大推乱七八糟的属性!
    use元素上大把乱七八糟属性

    难道我们要在网页中使用如此臃肿的use元素吗?

    我以小新的明义告诉你,绝对不会!

    小新的名义

    因为我昨晚在家折腾出了个工具,可以将illustrator生成SVG转换成web可用SVG Sprite.

    您可以狠狠地点击这里:illustrator生成SVG转换成web可用SVG Sprite工具demo

    上工具完整地址是:http://www.zhangxinxu.com/sp/svg.html 很好记忆,我站点域名+sp+svg.htmlspspecial的缩写,专门放工具用的。

    使用很简单:

    1. 把illustrator生成SVG所有代码拷贝到第一个框框里;
    2. 点击“转换萌萌哒”按钮,适用于SVG Sprite技术的新代码就出来了(左下的框框);同时,右侧显示了如何使用该SVG Sprite在web中真实实践;
    3. 左下角还有个红色的“导出该SVG”,就是字面意思,可以自定义名称,也可使用随机名称,为空即可;

    一开始的SVG Sprite使用示意demo就是使用这个工具生成的哦~ 见下缩略图:
    illustrator生成SVG转换工具使用截图

    注意:此工具值适用于illustrator生成的SVG, 水平有限,其他SVG转换十有八九会跛掉。没怎么测试,如果发现此工具转换出了问题,欢迎提醒,定会及时修复。另外,生成的SVG文件会不定期清理,请勿外链。

    我想想,还有没有什么问题……哦,为什么说此方法与CSS Sprite还要简单。

    因为,CSS Sprite还需要在CSS中使用background-position一个一个地定位,哦,天哪~ 如果没有工具的话,就纯粹搬砖的苦力活啊~

    但是,这里的SVG Sprite的定位,你只要在illustrator中把位置放好,illustrator这个软件就自动帮你定位好了。你只要在我的工具中转换下,生成下,然后在需要使用的地方使用:

    <svg><use xlink:href="#target" /></svg>

    就好了,用到CSS了吗?几乎没有,除了对SVG做尺寸限制以及改变图标的颜色。OK,这点程度的东西,小白设计师也可以轻松上手。

    从这一点来看,SVG又一次成为了明日之星!设计师只要在illustrator中做好图就可以了,完全没有从前那种帮重构切图的苦逼经历了,是不是要啤酒炸鸡庆祝下! 

    补充于2014年7月14日
    IcoMoon目前可以直接转换成SVG Sprite.

    1. 进入 http://icomoon.io/app/
    2. 点击”import icons”按钮:
      添加图标按钮
    3. 选择需要的图标:
      选择需要的图标
    4. 点击页面下面固定的SVG按钮:
      SVG按钮
    5. 点击打开的弹框的download按钮即可:
      下载SVG Sprite弹框以及按钮
    6. 下载的源文件中,有两个文件夹,其中sprites文件夹中,有合并好的SVG, png图标以及对应的demo, 这个绝不会迷路的,就不截图展示了。

    嘛,就此看来,这里才是老少皆宜,SVG Sprites整合最容易的地方。不过:

    1. 元素还是使用的g整合,svgstore以前也是,后来改成了symbol, 这里也可能在一段时日后也会修改,但并不确定;
    2. 名为sprites.html的demo页面的SVG还使用了viewbox做限制,我测试了,删掉似乎也没问题;

    补充于2014年12月21日
    注意注意:SVG Sprite技术是支持外链SVG文件的,例如:

    <svg viewBox="0 0 100 100"> <use xlink:href="defs.svg#icon-1"></use> </svg>

    所以,很多不喜欢内联SVG的小伙伴大可放心使用该技术。但是,美中不足的是,目前,所有的IE浏览器(包括IE11)还不支持获得外链SVG文件某个元件。Chrome/FireFox/Safari/Opera等浏览器都是OK的。

    补充于2015年3月18日
    SVG Sprite技术是支持直接Ajax请求SVG文件字符串的。因此,对于不支持外链的IE9+浏览器,可以直接:

    var ajax = new XMLHttpRequest();
    ajax.open("GET", "../201407/mytest.svg", true);
    ajax.onload = function(e) {
        document.body.insertAdjacentHTML("afterBegin", '<div style="display:none;">' + ajax.responseText + '</div>');
    }
    ajax.send();

    您可以狠狠地点击这里:Ajax请求SVG文件实现Sprites效果Demo

    例如,IE9浏览器下:
    IE9浏览器下SVG Ajax请求示意

    因此,大家大可不必担心SVG资源管理之类的问题。IE9等浏览器,一次Ajax成功后,可以直接本地存储,想想就很棒!

    补充于2016年10月27日
    部分华为Android手机,这种后置的ajax请求SVG写入方式无法呈现小图标,如果在页面头部一开始就有SVG文件代码资源,则没有此问题,图标不会显示不出来。

    要修复此方法,可以把SVG资源作为一个JS资源载入,例如,命名一个名叫sprite.js,里面代码大致如下:

    var SVG = '<svg xmlns="http://www.w3.org/2000/svg"><symbol id="icon-arrow-l" viewBox="0 0 8 16"><path d="M.146 7.646a.5.5 0 0 0 0 .708l7 7a.5.5 0 0 0 .708-.708l-7-7v.708l7-7a.5.5 0 0 0-.708-.708l-7 7z"/></symbol><symbol id="icon-arrow-r" viewBox="0 0 7 12"><path d="M6.146 6.354v-.708l-5.5 5.5a.5.5 0 0 0 .708.708l5.5-5.5a.5.5 0 0 0 0-.708l-5.5-5.5a.5.5 0 1 0-.708.708l5.5 5.5z"/></symbol><symbol ....</symbol></svg>';
    document.body.insertAdjacentHTML("afterBegin", '');

    然后在页面body标签的下面,直接:

    <script src="sprite.js"></script>

    类似下图:
    sprite.js放置在body标签的下面

    七、唯一的制约——兼容性

    SVG图标必定是未来的趋势。为何现在国内依然不温不火,不对,应该是还没有开始有温度。我觉得除了技术学习滞后性,浏览器兼容性是最关键的制约,毕竟IE8目前依然是大头(33.23%, 刚在百度流量研究院看到的数据)。

    如何破?按照我的心情,鸟它个毛线,我就手机上用用,不也挺好。静下来想想,不能意气用事,提一下IE7/IE8浏览器的处理方法吧~

    有些标签,浏览器识别,会忽略里面一些东西。例如SVG的desc元素,里面的内容一向不显示的。于是,对于IE7/IE8, 我们可以把对应图标的png图片放在其中,然后IE9+等支持SVG的浏览器就会忽略之,而IE7/IE8这些不识泰山的元素就会显示图片。拿礼物这个SVG举例:

    <svg class="webicon">
        <desc><img src="iconfont-baobei.png" width="16" height="16"></desc>
        <use xlink:href="#liwu"/>
    </svg>兑换礼物

    于是,在IE8下,就会是这样:
    IE8浏览器下效果

    其他靠谱浏览器依然是这样:
    SVG使用的图标效果

    于是,完美兼容了。只是活脱脱多了个标签,略败兴。当然,你也可以针对IE7/IE8使用CSS Sprite技术,原理类似,只是img标签换成其他i之类标签显示背景图,至少HTML这块会干净很多。

    八、结束语

    今年4月份的时候刚介绍过“CSS3图标图形生成技术”,如果说“font-face图标生成技术”是热门的话,那“CSS3图标生成技术”则属于偏门,受设计制约很大,而本文介绍的“SVG Sprite图标生成”则代表了未来。

    font-face在部分win系统下,字体较小的时候,锯齿问题很讨厌,苛刻的设计师无法忍受,甚至出现了响应式font-face这样的名堂,但是,据我观察,纯正的SVG图标是没有这个问题的,而且,SVG图标具备font-face几乎所有的优点,尺寸CSS可随意定制,颜色CSS可随意定制;且没有font-face异步加载延时渲染问题;同时没有某些浏览器下font-face跨域问题;更关键的是,SVG图标支持渐变,甚至彩色图标的。而font-face实现彩色图标,要一个一个拼起来,你以为贴马赛克啊!而且,SVG中每个path元素等可以独立控制,帅气的图标变换动画等的就是你来实现(add on 2014/7/18 这个页面N多SVG图标动画)!

    因此,各方面看,SVG完胜font-face,

    目前唯一的问题就是兼容成本(当然,业界还是有很多成熟的优雅降级技术,可参见我之前的文章“一些SVG向下兼容优雅降级技术”)。但是,随着浏览器的发展,SVG一定会迎来自己Web新舞台!

    感谢阅读,欢迎交流,踊跃纠错,多多赞助!

    (本篇完)

  • 相关阅读:
    linux 命令——19 find (转)
    linux 命令——18 locate (转)
    linux 命令——17 whereis(转)
    linux 命令——16 which(转)
    linux 命令——15 tail (转)
    linux 命令——14 head (转)
    Java for LeetCode 038 Count and Say
    Java for LeetCode 037 Sudoku Solver
    Java for LeetCode 036 Valid Sudoku
    Java for LeetCode 035 Search Insert Position
  • 原文地址:https://www.cnblogs.com/liangshuang/p/8203129.html
Copyright © 2011-2022 走看看