SVG Sprite 使用简介

SVG简介

SVG便可缩放矢量图形 (Scalable Vector Graphics)的简称, 是一种用来描述二维矢量图形的XML标记语言. SVG图形不依赖于分辨率, 所以图形不会由于放大而显示出明显的锯齿边缘.javascript

icon sprite

当咱们须要使用多个icon的时候, 为了节省请求和方便管理, 一般会把icon合并到一个文件中, 在使用时再经过必定的方法从icon集合文件中取出所需的图形并显示. 目前使用得最多的应该就是咱们所熟悉的CSS Sprite和Icon Font.css

CSS Sprite

CSS Sprite的原理是将多个icon按必定规律整理到一个图片文件中, 使用时利用background-imagebackground-position将图片中特定部分显示出来. CSS Sprite技术已经被普遍应用了很长的一段时间, 目前有许多自动化生成Sprite图片和CSS文件的工具, 例如(gulp.spritesmith)[github.com/twolfson/gu…].html

.icon1 {
    background-image: url(/res/icon1.png)
}
.icon1-increase {
    background-position: -10px -10px;
}复制代码
<i class="icon1 icon1-increase"/>复制代码

CSS Sprite技术成熟, 兼容性好, 可是缺点也比较明显. 如在实际需求中, 对应形状相同但颜色不一样的icon, 就须要为不一样颜色的icon各保存一份; 有时候须要对已有icon放大显示时, 发现锯齿严重, 那么又要再保存一份放大版的icon. 所以, Sprite文件会随着时间越变越大, 同时内容愈来愈乱, 逐渐变得难以管理.java

Icon Font

Icon Font的基本原理是将Icon定义为图片字体, 在CSS中用@font-face引入Icon Font自定义字体, 再利用font-family和字符码显示出指定的图标.git

@font-face {
    font-family: 'iconfont';
    src: url(/res/icon2.ttf) format('truetype');
}
.icon2 {
    font-family: 'iconfont';
}复制代码
<i class="icon2">&#33</i>复制代码

因为使用的是字体, 所以能够经过color, font-size设置icon的样式. Icon Font拥有比CSS Sprite图片更小的文件体积, 维护也比图片更方便, 可是icon font一般只能使用单一的颜色, 字体文件生成也比CSS Sprite更复杂.github

SVG Sprite

一般在使用SVG的时候, 咱们是直接写到svg标签当中:express

<svg xmlns="http://www.w3.org/2000/svg" width="150" height="100" viewBox="0 0 3 2">
        <rect width="1" height="2" x="0" fill="#008d46" />
        <rect width="1" height="2" x="1" fill="#ffffff" />
        <rect width="1" height="2" x="2" fill="#d2232c" />
    </svg>复制代码

此时SVG图形会直接在页面当中显示. SVG属性中, 能够利用(symbol)[developer.mozilla.org/zh-CN/docs/…, 并利用(use)[developer.mozilla.org/zh-CN/docs/…, 从而实现SVG Sprite的功能.gulp

SVG Sprite实例:浏览器

<svg style="height:0;width:0;display:none;" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <symbol id="icon-italy" width="150" height="100" viewBox="0 0 3 2">
        <rect width="1" height="2" x="0" fill="#008d46" />
        <rect width="1" height="2" x="1" fill="#ffffff" />
        <rect width="1" height="2" x="2" fill="#d2232c" />
    </symbol>

    <symbol id="icon-france" width="150" height="100" viewBox="0 0 3 2">
        <rect width="1" height="2" x="0" fill="#002496" />
        <rect width="1" height="2" x="1" fill="#ffffff" />
        <rect width="1" height="2" x="2" fill="#ee2839" />
    </symbol>
</svg>

<svg><use xlink:href="#icon-italy"/></svg>
<svg><use xlink:href="#icon-france"/></svg>复制代码

这样就实现了SVG Sprite.app

原理

经过devtool能够观察到, use标签是利用shadow dom实现的.

use.shadowdom
use.shadowdom

它经过xlink:href这个XML的attribute引用指定的SVG symbol, 在渲染时指定symbol标签中的内容就会被渲染显示在页面当中. 这意味着, 若是没法直接对use标签中的shadow dom进行访问和修改. 例如像use#rect这样的选择器是没法生效的, 所以不能经过通常的css选择器对use中图形不一样的部分进行控制.

CSS样式

更多的时候, 咱们一般都只须要改变图标的大小和颜色, 在SVG Sprite当中, 实现起来并不复杂.

  1. 大小

经过改变svg容器的大小, 能够轻松地对图标大小进行控制.

.icon{
    width: 120px;
    height: 80px;
}
.icon.icon-small{
    width: 60px;
    height: 40px;
}复制代码
<svg class="icon"><use xlink:href="#icon-italy"/></svg>
<svg class="icon icon-small"><use xlink:href="#icon-italy"/></svg>复制代码

svg.icon.size
svg.icon.size

  1. 颜色
  • 单色

颜色因为不能直接对use的shadow root中的图形标签进行选择, 所以在为图标定义颜色时须要利用fill: inherit这个一属性.

svg path{
    fill: inherit;
}
.icon2-green{
    fill: #008d46;
}
.icon2-red{
    fill: #dc352f;
}复制代码
<svg class="icon2 icon2-green">
    <use xlink:href="#icon-increase"/>
</svg>
<svg class="icon2 icon2-red">
    <use xlink:href="#icon-increase"/>
</svg>复制代码

svg.icon.color
svg.icon.color

利用inherit, 还能够定义stroke-width, stroke等属性.

  • 多色

除了对图标总体颜色进行定义之外, 还能够根据须要对图形不一样部分进行颜色定义. 这里使用到了css 的自定义属性(CSS Custom Properties).

这里须要对icon.svg进行修改, 将图形个部分的颜色设置为fill: var(--*[, default])的形式.

<symbol id="icon-flag" width="150" height="100" viewBox="0 0 3 2">
    <rect width="1" height="2" x="0" style="fill: var(--color0, #008d46)" />
    <rect width="1" height="2" x="1" style="fill: var(--color1, #fff)"/>
    <rect width="1" height="2" x="2" style="fill: var(--color2, #d2232c)"/>
</symbol>复制代码

定义css样式

.flag-belgium {
    --color0: #201b18;
    --color1: #f1ee3d;
    --color2: #dc352f;
}复制代码
<svg class="icon">
    <use xlink:href="#icon-flag"/>
</svg>
<svg class="icon flag-belgium">
    <use xlink:href="#icon-flag"/>
</svg>复制代码

svg.icon.color.parts
svg.icon.color.parts

除此之外, 还有其余一些样式定义的形式, 更详细的内容能够阅读Styling SVG Content with CSS.

实际使用

引用外部svg

上文介绍的是使用内联svg, 但其实还可使用外部svg的.

<svg class="icon">
    <use xlink:href="/res/svg/icon.svg#icon-flag"/>
</svg>复制代码

然而这种方法不兼容IE9~10, 但若是非要使用外部svg的形式, 能够引入一个pollyfillsvg4everybody, 当运行在不支持外部svg的状况下, 这个pollyfill会经过异步请求加载svg委文件并将其注入到页面当中, 将引用方法转换成内联svg.

在ftl中使用

能够在svg.ftl中定义一系列macro, 用以加载.svg文件.

<#macro svgicon path>
    <#include "${path}">
</#macro>

<#macro svgicon3 >
    <@svgicon "./icon3.svg"/>
</#macro>复制代码

在页面中引用demo.ftl:

<@svgicon1/>
<svg>
    <use xlink:href="#icon-italy"/>
</svg>复制代码

在regular中使用

xlink:href是使用了命名空间的XML特性, 若是是写在.html页面的标签, 该特性可以正常被浏览器解析并完成svg渲染. 若是该svg变量是经过DOM API建立出来的话, 则须要使用特定的方法进行处理(SVG with USE tag not rendering).

即须要利用createElementNSsetAttributeNS方法在建立的同时声明命名空间.

var use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#icon-increase');
document.querySelector('#svgid').appendChild(use);复制代码

只要是须要动态建立use元素, 都须要使用上面这种方法才能使SVG Sprite中的元素实例化. 但在目前的Regular(0.4.3)中, 不会对命名空间进行处理, 这意味着, 若是直接将<svg><use xlink:href/></svg>写在Regular组件的模版中时, 该标签是没法正常渲染的. 为此能够增长一个指令r-xlink:href以完成手动设置命名空间的操做.

Regular.directive('r-xlink:href', function (elem, val) {
    if (val&& val.type === 'expression') {
        this.$watch(val, function (newVal) {
            elem.setAttributeNS('http://www.w3.org/1999/xlink', 'href', newVal);
        });
    } else {
        elem.setAttributeNS('http://www.w3.org/1999/xlink', 'href', val);
    }
});复制代码

那么在组件模版中就能够像在普通.html中那样使用SVG Sprite了. 固然, 首先得确保SVG Sprite被写到页面中.

<svg>
    <use r-xlink:href="#icon-italy"/>
</svg>复制代码

在Regular的SVG 实践中获得了郑海波大神的指点, 不然得绕更大的路才能把问题解决, 在此表示感谢.

小结

对比前文提到的CSS Sprite和Icon Font, SVG有着明显的优点:

  • 放大缩小不会失真
  • 大小, 颜色等属性自定义灵活
  • 体积小, 同时管理方便

虽然SVG Sprite有着高度的灵活性, 但于此同时, SVG兼容性有待考究, 同时其渲染性能也不及图片和字体那么高, 可能在某些状况下不适用. 不过在通常的场景中, svg sprite还可以给开发带来很大的便利的.

参考

  1. SVG元素参考
  2. SVG with USE tag not rendering
  3. 将来必热:SVG Sprite技术介绍
  4. Styling SVG Content with CSS
  5. Icon System with SVG Sprites
相关文章
相关标签/搜索