SVG 教程
SVG(Scalable Vector Graphics,可缩放矢量图形)是一种基于 XML 的矢量图形格式,用于在网页上绘制直线、曲线、形状、文字等,并且任意缩放不失真。
矢量图 vs 位图
| 对比项 | SVG(矢量) | PNG/JPG(位图) |
|---|---|---|
| 缩放 | 任意缩放不失真 | 放大模糊、有锯齿 |
| 体积 | 图形简单时很小 | 固定像素,一般较大 |
| 编辑 | 代码/编辑器可改 | 需图像软件 |
| 动画 | 支持(CSS/SMIL) | 不支持 |
| 适用 | 图标、Logo、图表、插画 | 照片、复杂图像 |
SVG 的优点
- 清晰:Retina 屏上依然锐利
- 可编程:可被 JS/CSS 操作、动画
- 小体积:文本格式,可 gzip 压缩
- 无障碍:可加 title/desc 描述
一个最简单的 SVG
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
它绘制了一个圆心在 (50,50)、半径 40 的红色圆。
SVG 的应用场景
- 网站 Logo、图标系统
- 数据可视化(ECharts 底层)
- 图表、地图、动效插画
- UI 组件(进度环、图标按钮)
SVG 可以直接写在 HTML 中(内联),也可以作为 .svg 文件引用,还能用 <img>、CSS background 加载。
SVG 简介
本节介绍 SVG 的基本概念:坐标系、画布、与 HTML 的关系,以及浏览器的支持情况。
SVG 的坐标系
SVG 使用笛卡尔坐标系,但 y 轴向下:
- 原点 (0,0) 在画布左上角
- x 向右增大,y 向下增大
- 单位默认是像素(px)
<svg width="200" height="200">
<!-- (50,50) 距离左上角 50px 处 -->
<rect x="50" y="50" width="100" height="80" fill="skyblue" />
</svg>
SVG 的历史
- 1999 年 W3C 提出规范
- 2011 年成为 W3C 推荐标准
- SVG 2.0 仍在演进(2018 草案)
- 现代浏览器全部支持
SVG 元素 vs HTML 元素
| 对比项 | SVG | HTML |
|---|---|---|
| 用途 | 绘制图形 | 页面结构 |
| 命名空间 | W3C SVG | HTML |
| 标签 | circle/rect/path | div/span/p |
| 样式 | fill/stroke | color/background |
SVG 的三种使用方式
<!-- 1. 内联 -->
<svg><circle cx="10" cy="10" r="5"/></svg>
<!-- 2. img 引用 -->
<img src="icon.svg" alt="图标">
<!-- 3. CSS 背景 -->
<div style="background: url(icon.svg)"></div>
viewBox 视口
viewBox 定义内部坐标系,让图形可缩放适配容器:
<!-- 内部逻辑坐标 0-100,放大显示在 200px 容器中 -->
<svg width="200" height="200" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="red"/>
</svg>
内联 SVG 可以直接用 CSS 设置样式和动画,这是 <img> 方式做不到的。
SVG VSCode
本节介绍在 VS Code 中开发 SVG 的环境搭建:编辑、预览、调试一站完成。
1. 创建文件
在 VS Code 中新建 .svg 文件,编写图形代码。
2. 安装插件
| 插件 | 作用 |
|---|---|
| SVG(jock) | 语法高亮、智能提示 |
| SVG Preview | 实时预览 |
| SVG Viewer | 图形化查看 |
| Emmet(内置) | 快速输入标签 |
3. 实时预览
安装 SVG Preview 后,按 Cmd/Ctrl + Shift + V 或右键 → Open Preview,即可边写边看效果。
4. 基础模板
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200" viewBox="0 0 300 200">
<rect x="10" y="10" width="280" height="180" rx="8" fill="#f5f5f5" stroke="#333" stroke-width="2"/>
<text x="150" y="100" text-anchor="middle" font-size="20" fill="#333">Hello SVG</text>
</svg>
5. 在 HTML 中调试
也可以直接在 HTML 文件中内联 SVG 并打开浏览器调试:
<!DOCTYPE html>
<html>
<body>
<svg width="200" height="200">
<circle cx="100" cy="100" r="80" fill="orange"/>
</svg>
</body>
</html>
浏览器开发者工具也能调试内联 SVG:选中元素查看属性,动态修改样式和坐标,实时看到效果。
SVG 基本语法
SVG 的基本语法非常直观:每个图形元素由标签名 + 属性构成,属性决定位置、尺寸和样式。
基本语法结构
<svg width="400" height="300">
<!-- 属性:x/y 位置,width/height 尺寸,fill 填充色 -->
<rect x="20" y="20" width="150" height="100" fill="steelblue" />
<!-- 属性:cx/cy 圆心,r 半径 -->
<circle cx="250" cy="70" r="50" fill="tomato" />
</svg>
通用属性
| 属性 | 说明 | 示例 |
|---|---|---|
fill | 填充颜色 | fill="red" |
stroke | 描边颜色 | stroke="black" |
stroke-width | 描边宽度 | stroke-width="2" |
opacity | 整体透明度 | opacity="0.5" |
transform | 变换(平移/旋转/缩放) | transform="rotate(45)" |
颜色表示
<circle cx="30" cy="30" r="20" fill="red" /> <!-- 颜色名 -->
<circle cx="80" cy="30" r="20" fill="#ff0000" /> <!-- 十六进制 -->
<circle cx="130" cy="30" r="20" fill="rgb(255,0,0)" /> <!-- RGB -->
<circle cx="180" cy="30" r="20" fill="rgba(255,0,0,0.5)" /> <!-- 带透明度 -->
注释
<!-- 这是 SVG 注释 -->
大小写敏感
SVG 是 XML,标签和属性名区分大小写,且属性值建议加引号。
<!-- 正确 -->
<circle cx="50" cy="50" r="40"/>
<!-- 错误:标签名大小写不对 -->
<Circle cx="50" cy="50" r="40"/>
自闭合写法 <rect ... /> 在 XML/SVG 中是规范;在 HTML5 中不写斜杠也兼容。
SVG 在 HTML 中
SVG 可以直接嵌入 HTML,与页面元素无缝交互,这是它最重要的使用方式。
内联 SVG
<!DOCTYPE html>
<html>
<body>
<h1>我的 SVG 图标</h1>
<svg width="60" height="60" viewBox="0 0 60 60">
<circle cx="30" cy="30" r="25" fill="#4CAF50"/>
<text x="30" y="38" text-anchor="middle" fill="white" font-size="24">✓</text>
</svg>
</body>
</html>
用 CSS 控制内联 SVG
内联 SVG 的元素可以直接被 CSS 选中和样式化:
<style>
.icon { width: 48px; height: 48px; }
.icon:hover circle { fill: #ff9800; } /* 悬停变色 */
.icon circle { transition: fill 0.3s; }
</style>
<svg class="icon" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="#2196F3"/>
</svg>
img 方式引用
<img src="logo.svg" width="100" height="100" alt="Logo">
CSS 背景方式
.btn {
background: url("arrow.svg") no-repeat center;
background-size: 20px 20px;
}
三种方式对比
| 方式 | CSS 控制 | JS 控制 | 适用 |
|---|---|---|---|
| 内联 | ✅ | ✅ | 需要交互/动画 |
| img | 仅整体 | 仅整体 | 静态图标 |
| CSS 背景 | ✅ | ❌ | 装饰性图形 |
内联 SVG 里的元素可通过 document.querySelector 获取并操作,与操作普通 HTML 元素一样。
SVG 矩形
矩形(<rect>)是最基础的 SVG 形状之一,支持圆角。
基本矩形
<svg width="300" height="150">
<rect x="20" y="20" width="200" height="100" fill="steelblue" />
</svg>
圆角矩形
<svg width="300" height="150">
<!-- rx/ry 控制圆角半径 -->
<rect x="20" y="20" width="200" height="100" rx="20" ry="20" fill="#FFC107" />
</svg>
只填充 / 只描边 / 填充+描边
<svg width="400" height="120">
<rect x="10" y="10" width="100" height="80" fill="lightgreen" />
<rect x="140" y="10" width="100" height="80" fill="none" stroke="crimson" stroke-width="3" />
<rect x="270" y="10" width="100" height="80" fill="lightblue" stroke="navy" stroke-width="2" />
</svg>
透明度
<svg width="300" height="120">
<rect x="20" y="20" width="100" height="80" fill="red" opacity="1" />
<rect x="60" y="20" width="100" height="80" fill="red" opacity="0.5" />
<rect x="100" y="20" width="100" height="80" fill="red" opacity="0.2" />
</svg>
rect 全部属性
| 属性 | 说明 |
|---|---|
x / y | 左上角坐标(默认 0) |
width / height | 宽高(必填) |
rx / ry | 圆角半径(x/y 方向) |
fill | 填充色(默认黑色) |
stroke / stroke-width | 描边色/宽度 |
只设 rx 不设 ry 时,ry 默认等于 rx,画正圆角。
SVG 圆形
圆形(<circle>)用圆心和半径定义,是绘制点的理想选择。
基本圆形
<svg width="200" height="200">
<!-- cx/cy 圆心,r 半径 -->
<circle cx="100" cy="100" r="80" fill="#E91E63" />
</svg>
空心圆(描边)
<svg width="200" height="200">
<circle cx="100" cy="100" r="70" fill="none" stroke="#3F51B5" stroke-width="10" />
</svg>
多个圆组合(奥运五环风格)
<svg width="300" height="150">
<circle cx="80" cy="60" r="40" fill="none" stroke="#4285F4" stroke-width="8"/>
<circle cx="150" cy="60" r="40" fill="none" stroke="#EA4335" stroke-width="8"/>
<circle cx="220" cy="60" r="40" fill="none" stroke="#FBBC05" stroke-width="8"/>
</svg>
渐变圆
<svg width="200" height="200">
<defs>
<radialGradient id="grad">
<stop offset="0%" stop-color="#fff" />
<stop offset="100%" stop-color="#FF5722" />
</radialGradient>
</defs>
<circle cx="100" cy="100" r="80" fill="url(#grad)" />
</svg>
circle 属性速查
| 属性 | 说明 |
|---|---|
cx / cy | 圆心坐标(默认 0) |
r | 半径(必填) |
fill / stroke | 填充/描边 |
雷达图、进度环、头像背景等场景,圆形都是核心元素。
SVG 椭圆
椭圆(<ellipse>)与圆形类似,但 x/y 方向的半径可以不同。
基本椭圆
<svg width="300" height="200">
<!-- rx 水平半径,ry 垂直半径 -->
<ellipse cx="150" cy="100" rx="120" ry="60" fill="#9C27B0" />
</svg>
椭圆 vs 圆
| 对比项 | circle | ellipse |
|---|---|---|
| 半径 | r(单一) | rx + ry |
| 形状 | 正圆 | 可扁可长 |
偏心椭圆(rx > ry)
<svg width="400" height="150">
<ellipse cx="100" cy="75" rx="90" ry="30" fill="orange"/>
<ellipse cx="250" cy="75" rx="30" ry="60" fill="teal"/>
</svg>
带描边的椭圆
<svg width="300" height="200">
<ellipse cx="150" cy="100" rx="110" ry="55"
fill="none" stroke="#00BCD4" stroke-width="4" stroke-dasharray="10 6" />
</svg>
stroke-dasharray 让描边变成虚线,第一个数字是线段长,第二个是间隔。
ellipse 属性速查
| 属性 | 说明 |
|---|---|
cx / cy | 中心坐标(默认 0) |
rx | 水平半径(必填) |
ry | 垂直半径(必填) |
当 rx == ry 时,ellipse 与 circle 效果完全相同,日常画圆推荐直接用 circle。
SVG 直线
直线(<line>)通过两个端点坐标绘制,是最简单的 SVG 图形。
基本直线
<svg width="300" height="100">
<!-- x1 y1 起点,x2 y2 终点 -->
<line x1="20" y1="80" x2="280" y2="20" stroke="black" stroke-width="2" />
</svg>
横线与竖线
<svg width="300" height="200">
<!-- 水平线 -->
<line x1="10" y1="50" x2="290" y2="50" stroke="crimson" stroke-width="2"/>
<!-- 垂直线 -->
<line x1="150" y1="10" x2="150" y2="190" stroke="navy" stroke-width="2" stroke-dasharray="5 5"/>
</svg>
带端点标记的直线
<svg width="300" height="100">
<line x1="30" y1="50" x2="270" y2="50"
stroke="#673AB7" stroke-width="3"
stroke-linecap="round" />
</svg>
stroke-linecap:butt(平头,默认)、round(圆头)、square(方头)。
line 属性速查
| 属性 | 说明 |
|---|---|
x1 / y1 | 起点坐标(默认 0) |
x2 / y2 | 终点坐标(默认 0) |
stroke | 颜色(必填,否则看不见) |
stroke-width | 线宽 |
注意:<line> 没有 fill,颜色靠 stroke 设置,否则默认黑色不可见时会感觉"画不出线"。
SVG 多边形
多边形(<polygon>)通过一系列顶点坐标绘制闭合图形,自动连接首尾顶点。
基本多边形
<svg width="300" height="300">
<!-- points:一组"x,y"坐标对 -->
<polygon points="150,20 250,200 50,200" fill="#FF9800" />
</svg>
五角星
<svg width="300" height="300">
<polygon points="150,10 180,110 280,110 200,170 230,270
150,210 70,270 100,170 20,110 120,110"
fill="#FDD835" stroke="#F57F17" stroke-width="3" />
</svg>
六边形
<svg width="300" height="260">
<polygon points="150,10 265,80 265,190 150,260 35,190 35,80"
fill="none" stroke="#4CAF50" stroke-width="4" />
</svg>
菱形
<svg width="300" height="200">
<polygon points="150,20 260,100 150,180 40,100" fill="#3F51B5" />
</svg>
polygon 要点
points用空格或逗号分隔坐标对- 图形自动闭合(首尾相连)
- 支持 fill / stroke / opacity 等通用属性
想画不规则形状(气泡、对话框尾巴)时,polygon 比 path 更简单直接。
SVG 多段线
多段线(<polyline>)与 polygon 类似,但不自动闭合,常用于折线图、波形图。
基本多段线
<svg width="300" height="200">
<polyline points="20,160 80,120 140,140 200,60 260,90 290,30"
fill="none" stroke="#E91E63" stroke-width="3" />
</svg>
polyline vs polygon
| 对比项 | polyline | polygon |
|---|---|---|
| 闭合 | 不闭合 | 自动闭合 |
| 填充效果 | 不填(或填但缺闭合边) | 填充闭合区域 |
| 典型用途 | 折线图、走势 | 星形、多边形图标 |
折线图示例
<svg width="320" height="200">
<!-- 网格线 -->
<line x1="30" y1="170" x2="300" y2="170" stroke="#ccc"/>
<line x1="30" y1="120" x2="300" y2="120" stroke="#eee"/>
<line x1="30" y1="70" x2="300" y2="70" stroke="#eee"/>
<!-- 数据折线 -->
<polyline points="50,150 100,130 150,140 200,90 250,100 290,50"
fill="none" stroke="#2196F3" stroke-width="3"/>
<!-- 数据点 -->
<circle cx="50" cy="150" r="4" fill="#2196F3"/>
<circle cx="100" cy="130" r="4" fill="#2196F3"/>
<circle cx="150" cy="140" r="4" fill="#2196F3"/>
<circle cx="200" cy="90" r="4" fill="#2196F3"/>
<circle cx="250" cy="100" r="4" fill="#2196F3"/>
<circle cx="290" cy="50" r="4" fill="#2196F3"/>
</svg>
fill 设为 none 是 polyline 的常用做法;若想填充折线与底边围成的区域,可改用 polygon 并在末尾加回起点坐标。
SVG 路径
路径(<path>)是 SVG 最强大、最灵活的绘图元素,几乎所有复杂图形都能用它描述。
path 的命令
d 属性由命令字母 + 参数组成:
| 命令 | 含义 | 示例 |
|---|---|---|
M x y | 移动到某点(Move) | M 10 10 |
L x y | 画直线到某点(Line) | L 100 100 |
H x | 水平线 | H 150 |
V y | 垂直线 | V 150 |
C x1 y1 x2 y2 x y | 三次贝塞尔曲线 | C ... |
Q x1 y1 x y | 二次贝塞尔曲线 | Q ... |
A rx ry rot large sweep x y | 圆弧 | A 20 20 0 0 1 100 100 |
Z | 闭合路径 | Z |
直线路径(三角形)
<svg width="300" height="200">
<path d="M 150 20 L 250 180 L 50 180 Z"
fill="#FF5722" stroke="#BF360C" stroke-width="3" />
</svg>
圆角矩形路径
<svg width="300" height="150">
<path d="M 20 40 H 200 Q 220 40 220 60 V 110 Q 220 130 200 130 H 40
Q 20 130 20 110 V 60 Q 20 40 40 40 Z"
fill="#4CAF50" />
</svg>
贝塞尔曲线(爱心)
<svg width="300" height="260">
<path d="M 150 230 C 60 170 30 110 60 60 C 85 20 135 30 150 80
C 165 30 215 20 240 60 C 270 110 240 170 150 230 Z"
fill="#E91E63" />
</svg>
圆弧(半圆)
<svg width="300" height="200">
<path d="M 30 150 A 120 120 0 0 1 270 150" fill="none" stroke="#3F51B5" stroke-width="6"/>
</svg>
相对命令(小写)
小写命令基于当前点相对移动,更便于编写可平移的路径:
<!-- 等价于 M 50 50 L 150 50 L 100 150 Z -->
<path d="m 50 50 l 100 0 l -50 100 z" fill="teal"/>
复杂 path 通常由设计工具(Figma/Illustrator)导出,不必手写;理解命令能帮你读懂和微调导出的路径。
SVG 文本
文本(<text>)用于在 SVG 中绘制文字,支持丰富的排版属性。
基本文本
<svg width="300" height="100">
<text x="20" y="60" font-size="28" fill="#333">Hello SVG</text>
</svg>
文本对齐
<svg width="300" height="120">
<text x="150" y="40" text-anchor="start" font-size="20" fill="crimson">左对齐</text>
<text x="150" y="70" text-anchor="middle" font-size="20" fill="navy">居中</text>
<text x="150" y="100" text-anchor="end" font-size="20" fill="green">右对齐</text>
</svg>
字号与字体
<text x="20" y="40" font-family="Arial, sans-serif" font-size="24" font-weight="bold">加粗文字</text>
<text x="20" y="80" font-style="italic" font-size="20">斜体文字</text>
描边文字
<text x="20" y="70" font-size="40" font-weight="bold"
fill="none" stroke="#FF9800" stroke-width="1.5">轮廓字</text>
多行文本
用多个 <tspan> 控制每行:
<svg width="300" height="150">
<text x="20" y="40" font-size="18" fill="#333">
<tspan x="20" dy="0">第一行文字</tspan>
<tspan x="20" dy="28">第二行文字</tspan>
<tspan x="20" dy="28" fill="#E91E63">第三行(红色)</tspan>
</text>
</svg>
文字路径
让文字沿路径排列:
<svg width="400" height="200">
<defs>
<path id="curve" d="M 30 150 Q 200 30 370 150" fill="none"/>
</defs>
<text font-size="20" fill="#673AB7">
<textPath href="#curve">文字沿着弧线排列显示</textPath>
</text>
</svg>
text-anchor(对齐)配合 x=容器中点,可以实现水平居中;垂直居中可用 dominant-baseline="middle"。
SVG Stroke 属性
Stroke(描边)属性控制图形的轮廓:颜色、宽度、虚线、端点等。
基础描边
<svg width="300" height="120">
<rect x="20" y="30" width="200" height="60" fill="none"
stroke="#2196F3" stroke-width="4" />
</svg>
虚线描边
<svg width="300" height="200">
<!-- dasharray:线段长,间隔 -->
<line x1="20" y1="50" x2="280" y2="50" stroke="#333" stroke-width="4"
stroke-dasharray="10 5" />
<line x1="20" y1="100" x2="280" y2="100" stroke="#333" stroke-width="4"
stroke-dasharray="20 5 5 5" />
<line x1="20" y1="150" x2="280" y2="150" stroke="#E91E63" stroke-width="6"
stroke-dasharray="15 8" stroke-linecap="round" />
</svg>
端点样式(linecap)
| 值 | 效果 |
|---|---|
butt | 平头(默认) |
round | 圆头 |
square | 方头(比 butt 略长) |
连接点样式(linejoin)
<svg width="300" height="120">
<path d="M 30 90 L 70 30 L 110 90" fill="none" stroke="#333" stroke-width="12" stroke-linejoin="miter"/>
<path d="M 130 90 L 170 30 L 210 90" fill="none" stroke="#333" stroke-width="12" stroke-linejoin="round"/>
<path d="M 230 90 L 270 30 L 310 90" fill="none" stroke="#333" stroke-width="12" stroke-linejoin="bevel"/>
</svg>
动画描边(进度条效果)
<svg width="300" height="100">
<style>
.progress { stroke-dasharray: 300; stroke-dashoffset: 300;
animation: draw 2s forwards; }
@keyframes draw { to { stroke-dashoffset: 60; } }
</style>
<rect x="10" y="40" width="280" height="20" rx="10" fill="#eee"/>
<rect class="progress" x="10" y="40" width="280" height="20" rx="10"
fill="none" stroke="#4CAF50" stroke-width="20"/>
</svg>
stroke-dashoffset 动画是绘制"描边动画"的经典技巧:先把线全部"藏起来",再动画显示到目标长度。
SVG 滤镜
滤镜(<filter>)可以给 SVG 图形添加模糊、阴影、发光、扭曲等效果,实现复杂的视觉表现。
滤镜的基本结构
<svg width="300" height="200">
<defs>
<filter id="myFilter">
<!-- 这里放滤镜原语 -->
</filter>
</defs>
<rect x="50" y="50" width="200" height="100" fill="#2196F3" filter="url(#myFilter)"/>
</svg>
常用滤镜原语
| 原语 | 作用 |
|---|---|
feGaussianBlur | 高斯模糊 |
feDropShadow | 投影阴影 |
feOffset | 偏移 |
feFlood | 填充色块 |
feBlend | 混合 |
feColorMatrix | 颜色矩阵变换 |
高斯模糊
<svg width="300" height="150">
<defs>
<filter id="blur">
<feGaussianBlur stdDeviation="3" />
</filter>
</defs>
<rect x="50" y="40" width="200" height="80" fill="#FF9800" filter="url(#blur)"/>
</svg>
多滤镜叠加
<filter id="multi">
<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
<feOffset in="blur" dx="3" dy="3" result="shadow"/>
<feMerge>
<feMergeNode in="shadow"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
这个滤镜实现了"投影 + 原图"的合成效果。
滤镜比较消耗性能,避免在大量元素上叠加复杂滤镜;能用 CSS 的 filter 属性(如 blur()、drop-shadow())时优先用 CSS。
SVG 模糊效果
给图形添加模糊效果,能模拟景深、毛玻璃,或作为发光底衬。
高斯模糊滤镜
<svg width="300" height="150">
<defs>
<filter id="gblur">
<feGaussianBlur stdDeviation="5" />
</filter>
</defs>
<rect x="40" y="40" width="220" height="80" rx="12" fill="#4CAF50" filter="url(#gblur)"/>
</svg>
stdDeviation 值越大模糊越明显。
模糊程度对比
<svg width="360" height="120">
<defs>
<filter id="b1"><feGaussianBlur stdDeviation="0"/></filter>
<filter id="b2"><feGaussianBlur stdDeviation="3"/></filter>
<filter id="b3"><feGaussianBlur stdDeviation="8"/></filter>
</defs>
<circle cx="60" cy="60" r="35" fill="#E91E63" filter="url(#b1)"/>
<circle cx="180" cy="60" r="35" fill="#E91E63" filter="url(#b2)"/>
<circle cx="300" cy="60" r="35" fill="#E91E63" filter="url(#b3)"/>
</svg>
CSS 模糊(替代方案)
<style>
.blur-img { filter: blur(4px); }
</style>
<img class="blur-img" src="photo.jpg" width="300">
模糊发光效果
<svg width="200" height="200">
<defs>
<filter id="glow">
<feGaussianBlur stdDeviation="6" result="blur"/>
<feMerge>
<feMergeNode in="blur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<circle cx="100" cy="100" r="50" fill="#FFD700" filter="url(#glow)"/>
</svg>
发光效果 = 模糊副本 + 原图叠加,用 feMerge 把两者合成,是 SVG 常用技巧。
SVG 阴影
阴影让图形有立体感。SVG 有两种实现方式:滤镜 feDropShadow 或偏移 + 合成。
feDropShadow 阴影
<svg width="300" height="200">
<defs>
<filter id="drop">
<feDropShadow dx="4" dy="4" stdDeviation="4" flood-color="#000" flood-opacity="0.4"/>
</filter>
</defs>
<rect x="60" y="50" width="180" height="100" rx="10" fill="#fff" filter="url(#drop)"/>
</svg>
参数说明
| 属性 | 作用 |
|---|---|
dx / dy | 阴影偏移距离 |
stdDeviation | 模糊程度 |
flood-color | 阴影颜色 |
flood-opacity | 阴影透明度 |
彩色阴影
<svg width="300" height="200">
<defs>
<filter id="colorShadow">
<feDropShadow dx="3" dy="6" stdDeviation="5" flood-color="#9C27B0" flood-opacity="0.6"/>
</filter>
</defs>
<circle cx="150" cy="100" r="60" fill="#4CAF50" filter="url(#colorShadow)"/>
</svg>
传统方式(偏移+合成)
<filter id="oldShadow">
<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
<feOffset in="blur" dx="3" dy="3" result="off"/>
<feMerge>
<feMergeNode in="off"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
CSS 阴影(替代方案)
.card {
filter: drop-shadow(4px 4px 6px rgba(0,0,0,0.3));
}
给内联 SVG 加阴影,CSS 的 filter: drop-shadow() 最简单;复杂多色阴影再用 SVG 滤镜。
SVG 渐变 - 线性
线性渐变让颜色沿直线方向平滑过渡,是 SVG 最常见的渐变方式。
定义线性渐变
<svg width="300" height="150">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#FF512F" />
<stop offset="100%" stop-color="#DD2476" />
</linearGradient>
</defs>
<rect x="30" y="30" width="240" height="90" rx="8" fill="url(#grad1)" />
</svg>
渐变方向
<!-- 水平(默认) -->
<linearGradient id="gH" x1="0%" y1="0%" x2="100%" y2="0%">...</linearGradient>
<!-- 垂直 -->
<linearGradient id="gV" x1="0%" y1="0%" x2="0%" y2="100%">...</linearGradient>
<!-- 对角 -->
<linearGradient id="gD" x1="0%" y1="0%" x2="100%" y2="100%">...</linearGradient>
多色渐变
<linearGradient id="rainbow" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#f00"/>
<stop offset="33%" stop-color="#0f0"/>
<stop offset="66%" stop-color="#00f"/>
<stop offset="100%" stop-color="#f0f"/>
</linearGradient>
描边渐变
<svg width="300" height="150">
<defs>
<linearGradient id="strokeGrad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#1FA2FF"/>
<stop offset="100%" stop-color="#12D8FA"/>
</linearGradient>
</defs>
<rect x="30" y="40" width="240" height="80" rx="12"
fill="none" stroke="url(#strokeGrad)" stroke-width="6"/>
</svg>
渐变 vs 纯色
| 对比项 | 纯色 fill | 渐变 fill |
|---|---|---|
| 视觉 | 扁平 | 有层次 |
| 性能 | 更快 | 略慢 |
| 适用 | 简洁 UI | 按钮、Logo、图表 |
渐变定义放在 <defs> 中,通过 fill="url(#id)" 引用,可被多个元素复用。
SVG 渐变- 放射性
放射性渐变从中心点向外扩散颜色,适合做光晕、球体、按钮高光。
基本径向渐变
<svg width="200" height="200">
<defs>
<radialGradient id="rad">
<stop offset="0%" stop-color="#fff" />
<stop offset="100%" stop-color="#FF5722" />
</radialGradient>
</defs>
<circle cx="100" cy="100" r="80" fill="url(#rad)" />
</svg>
控制中心与半径
<radialGradient id="rad2" cx="30%" cy="30%" r="70%">
<stop offset="0%" stop-color="#FFEB3B"/>
<stop offset="100%" stop-color="#F57C00"/>
</radialGradient>
cx / cy 控制渐变中心(相对元素),r 控制扩散半径。
球体效果
<svg width="200" height="200">
<defs>
<radialGradient id="ball" cx="35%" cy="30%" r="75%">
<stop offset="0%" stop-color="#B3E5FC"/>
<stop offset="45%" stop-color="#2196F3"/>
<stop offset="100%" stop-color="#0D47A1"/>
</radialGradient>
</defs>
<circle cx="100" cy="100" r="80" fill="url(#ball)"/>
</svg>
多重 stop
<radialGradient id="multi">
<stop offset="0%" stop-color="#fff"/>
<stop offset="40%" stop-color="#FFC107"/>
<stop offset="100%" stop-color="#E65100"/>
</radialGradient>
线性 vs 径向
| 对比项 | linearGradient | radialGradient |
|---|---|---|
| 扩散方向 | 沿直线 | 由中心向外 |
| 关键属性 | x1 y1 x2 y2 | cx cy r |
| 典型效果 | 按钮渐变、横幅 | 球体、光晕、高光 |
中心点(cx cy)偏离几何中心(如 35%, 30%)能模拟"光源在斜上方"的效果,让球体更真实。
SVG 实例
综合运用所学,绘制一个完整实例:带渐变、阴影、文字和动画的 SVG 图标。
实例:仪表盘卡片
<svg width="300" height="220" viewBox="0 0 300 220">
<defs>
<linearGradient id="cardBg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#667eea"/>
<stop offset="100%" stop-color="#764ba2"/>
</linearGradient>
<filter id="shadow">
<feDropShadow dx="2" dy="4" stdDeviation="6" flood-opacity="0.3"/>
</filter>
</defs>
<!-- 卡片背景 -->
<rect x="30" y="30" width="240" height="160" rx="16" fill="url(#cardBg)" filter="url(#shadow)"/>
<!-- 进度环 -->
<circle cx="100" cy="110" r="45" fill="none" stroke="rgba(255,255,255,0.2)" stroke-width="10"/>
<circle cx="100" cy="110" r="45" fill="none" stroke="#fff" stroke-width="10"
stroke-linecap="round" stroke-dasharray="283" stroke-dashoffset="85"
transform="rotate(-90 100 110)"/>
<text x="100" y="118" text-anchor="middle" font-size="22" fill="#fff" font-weight="bold">70%</text>
<!-- 文字 -->
<text x="190" y="95" text-anchor="middle" font-size="16" fill="rgba(255,255,255,0.85)">完成率</text>
<text x="190" y="120" text-anchor="middle" font-size="20" fill="#fff" font-weight="bold">目标 100</text>
</svg>
实例解析
| 元素 | 作用 |
|---|---|
| linearGradient | 卡片渐变背景 |
| feDropShadow | 卡片投影 |
| circle × 2 | 进度环(底环 + 进度弧) |
| stroke-dasharray | 弧长 283(周长),进度偏移 85 = 70% |
| rotate(-90 ...) | 让进度从 12 点方向开始 |
| text × 3 | 百分比与说明文字 |
进度环原理
圆的周长 2πr = 2 × 3.14 × 45 ≈ 283。设置 stroke-dasharray="283" 后,用 stroke-dashoffset 隐藏一部分即可显示进度:70% 进度 = 283 × (1 - 0.7) ≈ 85。
用 JS 动态修改 stroke-dashoffset,就能做出丝滑的进度动画,这是很多仪表盘的实现方式。
SVG 参考手册
本节提供 SVG 常用元素与属性的参考速查,方便随时查阅。
形状元素
| 元素 | 用途 | 关键属性 |
|---|---|---|
<rect> | 矩形 | x y width height rx ry |
<circle> | 圆形 | cx cy r |
<ellipse> | 椭圆 | cx cy rx ry |
<line> | 直线 | x1 y1 x2 y2 |
<polyline> | 折线(不闭合) | points |
<polygon> | 多边形(闭合) | points |
<path> | 任意路径 | d |
<text> | 文本 | x y font-size text-anchor |
<g> | 分组 | —(可整体变换/样式) |
<defs> | 定义复用资源 | 渐变/滤镜/符号 |
<use> | 复用已定义元素 | href |
通用样式属性
| 属性 | 说明 |
|---|---|
fill | 填充色(none 表示不填充) |
fill-opacity | 填充透明度 0-1 |
stroke | 描边色 |
stroke-width | 描边宽度 |
stroke-dasharray | 虚线(线段长,间隔) |
stroke-linecap | 端点样式 butt/round/square |
stroke-linejoin | 连接样式 miter/round/bevel |
opacity | 整体透明度 |
transform | 变换 |
常用变换
transform="translate(x, y)" <!-- 平移 -->
transform="rotate(45)" <!-- 旋转(可带中心点 rotate(45 cx cy))-->
transform="scale(2)" <!-- 缩放 -->
transform="skewX(20)" <!-- 斜切 -->
viewBox 示例
<!-- viewBox: minX minY width height -->
<svg viewBox="0 0 100 100" width="200" height="200">
<rect x="25" y="25" width="50" height="50" fill="teal"/>
</svg>
完整规范可查阅 MDN SVG 文档(developer.mozilla.org),它是最权威的参考手册。
在线实例
本节整理一批在线 SVG 工具,帮助你在不写代码的情况下快速制作和调试 SVG。
可视化设计工具
| 工具 | 用途 |
|---|---|
| Figma | 专业 UI/矢量设计,可导出 SVG |
| Illustrator | 专业矢量绘图 |
| draw.io | 免费流程图/架构图,导出 SVG |
| Inkscape | 免费开源矢量编辑器 |
图标库
| 图标库 | 说明 |
|---|---|
| Font Awesome | 经典图标库 |
| Material Icons | Google 风格图标 |
| Tabler Icons | 开源免费 SVG 图标 |
| Lucide | 轻量开源图标(Vue/React 友好) |
在线工具
- yqnn.github.io/svg-path-editor:path 可视化编辑器
- svgoptimizer.com:SVG 压缩优化
- caniuse.com:浏览器兼容性查询
- SVGOMG:SVG 优化(svgomg.netlify.app)
实战建议
- 简单图标:从图标库复制 SVG 代码直接使用
- 自定义图形:Figma/draw.io 画好后导出
- 动画:用 CSS 或 SMIL 在内联 SVG 上实现
- 优化:上线前用 SVGOMG 压缩体积
下载的图标 SVG 常含冗余代码,用 SVGOMG 优化后再引入项目,可显著减小体积。