SVG
SVG 是一种 XML 语言,类似于 XHTML,可以用来绘制矢量图形
Look
下面是用 SVG 技术画的一个简单的图形,包括了圆形、矩形和文本元素
资源引用
svg 可以嵌入到 HTML 当中,就像上面的 plaground 中的例子,直接把 SVG 标签嵌入到 HTML 标签中
TIP
在允许的情况下,这其实是最好的使用方式,既在文档中保留了 SVG 的 DOM 结构,又和其他元素在同一个上下文中
当我们的 SVG 资源是一个网络资源的时候,我们可以使用 <img>、<object>、<iframe> 标签引用 SVG 资源:
<img src="/logo.svg" />
<object data="/logo.svg" type="image/svg+xml" />
<iframe src="/logo.svg" />这三种方式产生的结果有些不一样,当使用 img 标签渲染 SVG,浏览器会将 SVG 当作图像处理,而不是解析其中的 DOM 结构,这意味着无法获取 SVG 中 DOM 结构,自然也通过 CSS 选择器改变样式
所以我们可以选择 object 或者 iframe 标签来渲染,二者工作的方式类似:浏览器会将 SVG 当作一个独立的文档来处理,所以我们就可以看到结果
下面就是三者在浏览器中渲染出的 DOM 结构示意:
<img src="/logo.svg" /><object data="/logo.svg" type="image/svg+xml">
#document
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" viewBox="0 0 512 512" xml:space="preserve">
...
</svg>
</object><iframe src="/logo.svg">
#document
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" viewBox="0 0 512 512" xml:space="preserve">
...
</svg>
</iframe>命名空间
您可以注意到上面的 SVG 标签中,带有 xmlns 和 xmlns:xlink 等属性,这是和 SVG 命名空间有关的部分
SVG 是一种 XML 语言,或者说说 XML 的一种方言,W3C 的长期目标是使不同类型的基于 XML 的内容能够在同一个 XML 文件中混合使用
方言
XHTML 、RSS 和 MathML 等,它们都是 XML 的方言。当处于同一个 XML 中的时候,因为它们各自有着自己的规则。很容易存在解析冲突等问题,比如在 XHTML 和 SVG 都有一个 <title>标签,解析器不知道应该以 XHTML 还是 SVG 的规范来解析它
因此:需要通过给标签显式的「命名空间声明」告诉解析器它属于哪个方言
<svg xmlns="http://www.w3.org/2000/svg">
<rect />
<circle />
</svg>之所以叫做命名空间是因为 xmlns 确实创建了一个空间的概念,也就是说,上面 SVG 中的 rect 和 circle 标签都会以 http://www.w3.org/2000/svg 规范来解析
我们最常见和常用的空间就是 http://www.w3.org/2000/svg,看起来它是一个 URI,所以常常被称作 namespace URI,但是实际不承担链接跳转的任务,仅仅作为一个字符串标识符。
空间覆盖
空间之内还可以创建其他的空间,例如下面的 SVG 将会使用指定的新的命名空间
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<!-- some XHTML tags here -->
<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="200px">
<!-- some SVG tags here -->
</svg>
<!-- some XHTML tags here -->
</body>
</html>xlink
用于描述 XML 与 XML 或其他文档之间的链接。它的一些行为留给“方言”实现来确定如何处理,已经不推荐使用了
XLink 提供了一种在 XML 文档中创建链接的标准方式,这也包括了在 SVG 中的应用,常常在 SVG 标签上声明 xmlns:xlink 属性
xlink 有几个属性,过去常用的属性是 xlink:href,用于指定元素的超链接目标
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100">
<!-- 创建超链接到外部网页 -->
<a xlink:href="https://github.com/peterroe">
<rect width="100" height="100" fill="#D39C6D" />
</a>
<!-- 创建超链接到另一个 SVG 文件 -->
<a xlink:href="/logo.svg" target="_blank">
<circle cx="50" cy="50" r="40" fill="#664D44" />
</a>
</svg>现代 SVG 和 HTML5 已经支持超链接属性 href 而无需特定的命名空间,但在一些较旧的文档和实现中,你可能仍然会看到使用 xlink:href 的方式。但是在现代的文档中,你可以直接使用 href 属性而不添加 xlink 命名空间声明
Element
SVG 元素的默认宽高是 300 和 150,下面是一个例子(样式写法基于 UnoCss)
<svg bg-red></svg>下面介绍一些 SVG 中的基本的元素
TIP
在例子中,为方便观察,右侧渲染的 SVG 标签会有一个默认的边框和固定 150 和 100 的宽高,在左侧的示例代码中不会展示,CSS 如下:
svg {
border: 1px solid var(--vp-c-brand-1);
width: 150px;
height: 100px;
}circle
| 属性 | 功能 |
|---|---|
| cx | 圆心横坐标(相对左上角) |
| cy | 圆心纵坐标(相对左上角) |
| r | 半径 |
| fill | 圆填充的颜色(默认是黑色) |
| stroke | 圆框的颜色 |
| stroke-width | 圆框的宽度 |
<svg>
<circle cx="40" cy="40" r="30" fill="#AE9EE8" />
</svg>rect
| 属性 | 功能 |
|---|---|
| x | 左上角点的横坐标(相对左上角) |
| y | 左上角点的纵坐标(相对左上角) |
| height | 高度 |
| width | 宽度 |
| rx | 矩形的水平角半径 |
| ry | 矩形的垂直角半径,默认和 rx 相同 |
| fill | 填充的颜色 |
<svg>
<rect
x="10" y="10" width="80" height="60" rx="10"
fill="skyblue"
/>
</svg>line
| 属性 | 功能 |
|---|---|
| x1 | 第一个点的横坐标 |
| y1 | 第一个点的纵坐标 |
| x2 | 第二个点的横坐标 |
| y2 | 第二个点的纵坐标 |
| stroke | 线的颜色 |
<svg>
<line
x1="10" y1="10"
x2="60" y2="70" stroke="gray"
/>
</svg>g
g 元素意为 group,用于包裹其他 SVG 元素,以便赋予相同的属性
<svg>
<g fill="white" stroke="green" stroke-width="5">
<circle cx="40" cy="40" r="25" />
<circle cx="60" cy="60" r="25" />
</g>
</svg>path
path 元素是定义形状的通用元素,所有基本形状都可以使用 path 元素创建。同时,它的规则也非常的复杂
属性 d 用于描述路径,内置了多种命令来辅助我们绘制路径
TIP
path 中的,只是为了提升可读性,并无实质格式要求,不影响最终结果
| 命令 | 含义 | 参数 | 描述 |
|---|---|---|---|
| M | MoveTo | X Y | 移动当前点位置到(X,Y) |
| L | LineTo | X Y | 当前点位置向(X,Y)连直线 |
| H | Horizontal LineTo | X | 当前点画一条水平线到 x 坐标为 X |
| V | Vertical LineTo | Y | 当前点画一条垂直线到 x 坐标为 Y |
| C | CurveTo | C1x C1y, C2x C2y,X Y | 以(C1x,C1y)和(C2x,C2y)为控制点,画一条曲线到(X,Y) |
| Q | Quadratic Bezier CurveTo | Cx Cy, X Y | 以 Cx 和 Cy 为控制点,画一条曲线到(X,Y) |
| A | Elliptical Arc | rx ry, xar, laf, sf, x, y | rx半长轴的长度,ry半短轴的长度,xar旋转角度,laf大弧标志,sf扫描标志,(x,y)终点 |
| Z | ClosePath | 无 | 结束 path,连接起点,从而形成闭环路径,便于填充颜色 |
<svg>
<path stroke="blue" fill="white" d="
M10 20
L30 40
H 50
V 50
C80 50, 50 80, 80, 80
Q80 50, 100 50
A30 40, 0, 0, 0, 140, 20
Z
"></path>
</svg>对三次贝塞尔曲线不了解的可以跳转这个 playground,它有两个控制轴。
二次贝塞尔曲类似,和三次的区别就是只有一个控制轴
ViewBox
这个属性可以截取 SVG 中某个区域直接放大显示
举个例子,有一个长款为 100 的方形 SVG,其内部也有一个方形 rect 元素
<svg width="100" height="100">
<rect
x="10" y="10" width="30" height="30"
fill="skyblue"
/>
</svg>通过 viewBox 属性,我们可以让放大 rect 这一块区域,充满整个 SVG:
<!-- 设置 viewBox 的区域就是 rect 的区域 -->
<svg
width="100" height="100" viewBox="10 10 30 30"
>
<rect
x="10" y="10" width="30" height="30"
fill="skyblue"
/>
</svg>当然,上面的情况是 viewBox 的比例和 SVG 的完全比例一样的理想情况。在实际情况中,很有可能它们的比例是不一样的,因此我们需要去定义 viewBox 放大后,如何去适应 SVG 的区域
我们通过 preserveAspectRatio 属性去定义,它的值由空格分隔的两个值组合而成,例如:
<svg preserveAspectRatio="xMidYMid meet"></svg>
<svg preserveAspectRatio="xMaxYMid slice"></svg>第一个值表示,viewBox 如何与 SVG viewport 对齐;第二个值表示,如何维持高宽比(如果有)
其中,第1个值又是由两部分组成的:
| 值 | 含义 |
|---|---|
| xMin | viewport 和 viewBox 左边对齐 |
| xMid | viewport 和 viewBox x轴中心对齐 |
| xMax | viewport 和 viewBox 右边对齐 |
| YMin | viewport 和 viewBox 上边缘对齐。注意Y是大写。 |
| YMid | viewport 和 viewBox y轴中心点对齐。注意Y是大写。 |
| YMax | viewport 和 viewBox 下边缘对齐。注意Y是大写。 |
第二部分的值支持下面三个:
| 值 | 含义 |
|---|---|
| meet | 保持纵横比缩放 viewBox 适应 viewport |
| slice | 保持纵横比同时比例小的方向放大填满 viewport |
| none | 扭曲纵横比以充分适应 viewport |
我们直接上示例:
<svg width="300" height="150">
<circle
cx="40" cy="40" r="20"
fill="skyblue"
/>
</svg>为了便于观察,我们再次将 viewBox 设定为 rect 的区域:
<svg width="300" height="150" viewBox="20 20 40 40">
<circle
cx="40" cy="40" r="20"
fill="skyblue"
/>
</svg>此时我们看到
- viewBox 的比例是 40/40 = 1
- SVG viewport 的比例是 300/150 = 3/2
viewBox 和 SVG viewport 的比例不一致,而 preserveAspectRatio 的默认值是 xMidYMid meet
所以我们看到的效果是横向和竖向居中,保持 viewBox 的纵横比缩放适应 viewport
我们再来看看 preserveAspectRatio 其他值的效果
<!-- xMin 效果:viewport和viewBox左边对齐 -->
<svg
width="300" height="150" viewBox="20 20 40 40"
preserveAspectRatio="xMinYMid meet"
>
<circle
cx="40" cy="40" r="20"
fill="skyblue"
/>
</svg>
<!-- meet 效果:缩放viewBox适应viewport(默认) -->
<svg
width="300" height="150" viewBox="40 40 70 20"
preserveAspectRatio="xMidYMid meet"
>
<rect
x="40" y="40" width="70" height="20"
fill="skyblue"
/>
</svg>
<!-- slice 效果:向比例小的方向放大 -->
<svg
width="300" height="150" viewBox="40 40 70 20"
preserveAspectRatio="xMidYMid slice"
>
<rect
x="40" y="40" width="70" height="20"
fill="skyblue"
/>
</svg>
<!-- none 效果:拉伸 viewBox 填满
此时 xMidYMin 已无效果,所以不需要写 -->
<svg
width="300" height="150" viewBox="40 40 70 20"
preserveAspectRatio="none"
>
<rect
x="40" y="40" width="70" height="20"
fill="skyblue"
/>
</svg>