svg与图标icon
可缩放矢量图形(Scalable Vector Graphics , SVG) ,作为一种矢量图 ,它最大的特性是可以随意放大而不失真:
矢量图是根据几何特性来绘制图形,矢量可以是一个点或一条线,矢量图只能靠软件生成,文件占用内在空间较小,因为这种类型的图像文件包含独立的分离图像,可以自由无限制的重新组合。它的特点是放大后图像不会失真,和分辨率无关,适用于图形设计、文字设计和一些标志设计、版式设计等。
Inline Svg
Html 为我们提供了 Inline Svg 标签,我们可以很容易的将 svg 图片嵌入 html 页面中:
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<svg viewBox="0 0 1024 1024" width="48" height="48">
<path
d="M923 283.6c-13.4-31.1-32.6-58.9-56.9-82.8-24.3-23.8-52.5-42.4-84-55.5-32.5-13.5-66.9-20.3-102.4-20.3-49.3 0-97.4 13.5-139.2 39-10 6.1-19.5 12.8-28.5 20.1-9-7.3-18.5-14-28.5-20.1-41.8-25.5-89.9-39-139.2-39-35.5 0-69.9 6.8-102.4 20.3-31.4 13-59.7 31.7-84 55.5-24.4 23.9-43.5 51.7-56.9 82.8-13.9 32.3-21 66.6-21 101.9 0 33.3 6.8 68 20.3 103.3 11.3 29.5 27.5 60.1 48.2 91 32.8 48.9 77.9 99.9 133.9 151.6 92.8 85.7 184.7 144.9 188.6 147.3l23.7 15.2c10.5 6.7 24 6.7 34.5 0l23.7-15.2c3.9-2.5 95.7-61.6 188.6-147.3 56-51.7 101.1-102.7 133.9-151.6 20.7-30.9 37-61.5 48.2-91 13.5-35.3 20.3-70 20.3-103.3 0.1-35.3-7-69.6-20.9-101.9z">
</path>
</svg>
</body>
</html>
注释:
viewBox
定义了svg
的视图容器,后文详细讨论 -> viewBox .- svg 是由点和线构成的矢量图,
path
属性定义了这些点和线的位置。
因为矢量图的特点,我们可以很容易的改变这些点和线的颜色,从而非常容易的修改 svg 图片的颜色:
<svg viewBox="0 0 1024 1024" width="48" height="48">
<path
fill="red"
d="...">
</path>
</svg>
进一步,我们可以将这个 svg 图标自定义为一个组件来使用,比如用 react
:
// heart.tsx
import React from "react"
interface IProps {
color: string
}
const HeartIcon : React.FC<IProps> = (props) => {
const color = props.color
return (
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4014" data-darkreader-inline-fill="" width="48" height="48"><path ... fill={color}></path></svg>
)
}
export default HeartIcon
批量图标
阿里巴巴矢量图标库对项目量级的图标引入提供了两种解决方案,第一种是使用 @font-face ,它允许我们为项目引入自定义的字体文件。并且可以通过 font-family
使用自定义字体。
图标和字体本质上都可以用点和线来构成,因此各个 os 的字体系统本身就支持一些图标的表示,比如 windows就可以直接输入 emoji . 因此,只要引入图标生成的字体文件,我们就可以在项目中使用这些图标了。
@font-face {font-family: 'iconfont';
src: url('iconfont.eot');
src: url('iconfont.eot?#iefix') format('embedded-opentype'),
url('iconfont.woff') format('woff'),
url('iconfont.ttf') format('truetype'),
url('iconfont.svg#iconfont') format('svg');
}
.iconfont{
font-family:"iconfont" !important;
font-size:16px;font-style:normal;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
-moz-osx-font-smoothing: grayscale;}
<i class="iconfont">3</i>
而另一种引入批量图标的方式就是我们本文讨论的 svg
方式。它的核心是先通过 symbol 元素定义 svg
模板,然后在要使用图标的地方使用 use元素 copy 之前定义的模板,渲染 svg 图标。它看起来像这样:
<body>
<svg style="border: 1px solid #000;">
<symbol id="myDot" viewBox="0 0 1024 1024" width="48" height="48">
<path ...>
</path>
</symbol>
</svg>
<svg>
<use href="#myDot" fill="red" />
</svg>
</body>
我们接下来要解决几个疑问:
- 我们的模板
symbol
虽然没有显示,但它的容器svg
却默认占了一块空间,我们用border
将其标注了出来。怎么怎么将其隐藏掉呢? viewBox
属性是干什么用的呢?如果你通过搜索引擎去查找API文档,你会发现它的四个值分别是 【min-x
,min-y
,width
andheight
】 ,min-x,min-y
是什么? 我们不是已经定义了symbol
元素的width,height
属性了吗?为什么在viewBox
中又要在定义一次?- 我们如何自定义
svg
的颜色和大小呢? use
是在什么范围内寻找对应的模板标签symbol
呢?
接下来我们一一讨论这些疑问。
额外的svg
这是个很容易解决的问题,通过绝对定位将其隐藏掉:
<svg style="position: absolute;width: 0;height: 0;overflow: hidden;">
<symbol id="myDot" viewBox="0 0 1024 1024" width="48" height="48">
<path ...>
</path>
</symbol>
</svg>
viewBox
viewBox
的作用实际上可以分成:【截图】+【缩放】。
比如上面的 symbol
元素,它的容器大小是 width="48" height="48"
. 那么 viewBox = "0 0 1024 1024"
的意思是:从坐标轴x = 0 , y = 0 出发,从 path
元素截取长1024px,宽1024px 的内容, 并将其按容器大小(长宽48px)等比缩放,放入容器中。
关于更详细的 viewBox
的解释可以阅读 svg中viewbox图解分析 这篇文章。
如何自定义 svg
的颜色和大小?
use
元素会 copy
一份 symbol
元素,并将其属性并入拷贝的 symbol
元素上。因此我们可以在 use
上定义 fill
属性来定义 svg
的填充颜色:
<use href="#myDot" fill="red" />
它会转换为:
<symbol id="myDot" fill="red" viewBox="0 0 1024 1024" width="48" height="48">
</symbol>
而 symbol
内的 path
元素会继承 symbol
的 fill
属性,因此 path
上的点和线也拥有了填充的颜色。
类似的,我们也可以在 use
上定义 width,height
属性,但要注意 svg
在这里是一个容器,我们通常要定义容器和里面图案两者的大小。比如 svg
的默认长是 300 px ,宽是 150 px,如果我们把图案设置的过大:
<svg>
<use href="#myDot" fill="red" width="512" height="512" />
</svg>
因此我们还要给 svg
加上 class
样式:
<svg style="width: 512px;height: 512px;">
<use href="#myDot" fill="red" width="512" height="512" />
</svg>
use
是在什么范围内寻找对应的模板标签 symbol
呢?
根据 MDN的介绍:
The use of
<symbol>
elements for graphics that are used multiple times in the same document adds structure and semantics.
简单来说,只要在同一文档下,<symbol>
元素可以被实例化多次来使用。这一点在我们使用 use
时也可以发现,它是通过 document.getElementById
的语法糖 #
来匹配对应的 symbol
的,因此当然它的查找范围是同一个 html
文件,同一个文档内。
阿里巴巴矢量图标库具体是如何使用 svg 引入批量图标的?
它会为图标库生成一个 JavaScript 脚本文件,简化后大概为:
!(function (l) {
var e,
d =
'<svg><symbol id="iconadd1" viewBox="0 0 1024 1024"><path ... ><path /></symbol><symbol id="iconadd1" viewBox="0 0 1024 1024"><path ... ><path /></symbol><symbol id="iconadd1" viewBox="0 0 1024 1024"><path ... ><path /></symbol></svg>',
t = (e = document.getElementsByTagName("script"))[
e.length - 1
].getAttribute("data-injectcss");
if (t && !l.__iconfont__svg__cssinject__) {
l.__iconfont__svg__cssinject__ = !0;
try {
document.write(
"<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>"
);
} catch (e) {
console && console.log(e);
}
}
(function () {
var e, t, n, i, o, a;
((e = document.createElement("div")).innerHTML = d),
(d = null),
(t = e.getElementsByTagName("svg")[0]) &&
(t.setAttribute("aria-hidden", "true"),
(t.style.position = "absolute"),
(t.style.width = 0),
(t.style.height = 0),
(t.style.overflow = "hidden"),
(n = t),
(i = document.body).firstChild
? ((o = n), (a = i.firstChild).parentNode.insertBefore(o, a))
: i.appendChild(n));
});
})(window);
注释:
d
表示定义svg
和symbol
, 它被innerHTML
写入一个创建的div
中- 从这个
div
中取出刚刚定义的svg
元素,并设置绝对定位,隐藏模板svg
. - 将这个
div
插入document.body
中
因此我们在 SPA 中引入这个 js
文件,因为整个 SPA 项目只有一个 document,因此我们能够在整个项目中通过 use
引入这些图标。
参考:
转载自:https://juejin.cn/post/7247045913980764215