SVG便可缩放矢量图形 (Scalable Vector Graphics)的简称, 是一种用来描述二维矢量图形的XML标记语言. SVG图形不依赖于分辨率, 所以图形不会由于放大而显示出明显的锯齿边缘.javascript
当咱们须要使用多个icon的时候, 为了节省请求和方便管理, 一般会把icon合并到一个文件中, 在使用时再经过必定的方法从icon集合文件中取出所需的图形并显示. 目前使用得最多的应该就是咱们所熟悉的CSS Sprite和Icon Font.css
CSS Sprite的原理是将多个icon按必定规律整理到一个图片文件中, 使用时利用background-image
和background-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定义为图片字体, 在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">!</i>复制代码
因为使用的是字体, 所以能够经过color
, font-size
设置icon的样式. Icon Font拥有比CSS Sprite图片更小的文件体积, 维护也比图片更方便, 可是icon font一般只能使用单一的颜色, 字体文件生成也比CSS Sprite更复杂.github
一般在使用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实现的.
它经过xlink:href
这个XML的attribute
引用指定的SVG symbol
, 在渲染时指定symbol
标签中的内容就会被渲染显示在页面当中. 这意味着, 若是没法直接对use
标签中的shadow dom进行访问和修改. 例如像use#rect
这样的选择器是没法生效的, 所以不能经过通常的css选择器对use
中图形不一样的部分进行控制.
更多的时候, 咱们一般都只须要改变图标的大小和颜色, 在SVG Sprite当中, 实现起来并不复杂.
经过改变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>复制代码
颜色因为不能直接对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>复制代码
利用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>复制代码
除此之外, 还有其余一些样式定义的形式, 更详细的内容能够阅读Styling SVG Content with CSS.
上文介绍的是使用内联svg, 但其实还可使用外部svg的.
<svg class="icon">
<use xlink:href="/res/svg/icon.svg#icon-flag"/>
</svg>复制代码
然而这种方法不兼容IE9~10, 但若是非要使用外部svg的形式, 能够引入一个pollyfillsvg4everybody, 当运行在不支持外部svg的状况下, 这个pollyfill会经过异步请求加载svg委文件并将其注入到页面当中, 将引用方法转换成内联svg.
能够在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>复制代码
xlink:href
是使用了命名空间的XML特性, 若是是写在.html
页面的标签, 该特性可以正常被浏览器解析并完成svg渲染. 若是该svg变量是经过DOM API建立出来的话, 则须要使用特定的方法进行处理(SVG with USE tag not rendering).
即须要利用createElementNS
和setAttributeNS
方法在建立的同时声明命名空间.
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还可以给开发带来很大的便利的.