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新舞台!

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

    (本篇完)

  • 相关阅读:
    浙江理工2015.12校赛-F Landlocked
    浙江理工2015.12校赛-G Jug Hard
    浙江理工2015.12校赛-B 七龙珠
    浙江理工2015.12校赛-A
    Smallest Bounding Rectangle
    Just a Hook(HDU1698 线段树的简单应用)
    覆盖的面积(HDU 1255 线段树)
    Prime Query (ZOJ 3911 线段树)
    JuQueen(线段树 lazy)
    2015弱校联盟(2)
  • 原文地址:https://www.cnblogs.com/liangshuang/p/8203129.html
Copyright © 2011-2022 走看看