一、什么是 SVG?
SVG(Scalable Vector Graphics,可缩放矢量图形)是一种用 XML 代码描述图形 的格式。你写的不是像素点,而是一行行类似 HTML 的标签,浏览器读取这些标签后渲染出图形。
核心特点:
-
矢量:放大缩小不失真,和分辨率无关
-
代码驱动:纯文本,可读、可编辑、可程序化生成
-
DOM 元素:在 HTML 中直接内嵌,可以被 CSS 和 JavaScript 操作
-
文件极小:图标类图形通常只有几百字节
一句话理解:SVG 就是用代码画图,而不是用像素拼图。
二、SVG vs 位图(PNG/JPG)
| 对比项 | SVG(矢量图) | PNG / JPG(位图) |
|---|---|---|
| 本质 | 数学公式描述图形(坐标、路径) | 像素矩阵,每个像素一个颜色值 |
| 放大效果 | 始终清晰,不失真 | 放大后出现马赛克/模糊 |
| 文件大小 | 简单图形极小(几百字节) | 与分辨率正相关,通常更大 |
| 可编辑性 | 直接改代码就能修改图形 | 需要图像编辑软件(PS 等) |
| 适用场景 | 图标、Logo、图表、示意图、教学图形 | 照片、复杂渐变纹理 |
| 动画 | 原生支持(CSS/SMIL/JS) | 需要 GIF 或视频格式 |
三、SVG 基本结构
3.1 最小可用 SVG
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<circle cx="100" cy="100" r="50" fill="red" />
</svg>
这段代码做了什么:
-
<svg>:根元素,声明这是一个 SVG 图形 -
xmlns:XML 命名空间,告诉浏览器这是 SVG 标准 -
width / height:画布尺寸 -
<circle>:画一个圆,圆心 (100,100),半径 50,红色填充
3.2 viewBox —— 理解 SVG 的坐标系
viewBox 是 SVG 中最重要的概念之一,它定义了内部坐标系:
<svg viewBox="0 0 100 100" width="200" height="200">
<circle cx="50" cy="50" r="25" fill="blue" />
</svg>
关键理解:
-
viewBox="0 0 100 100":内部坐标从 (0,0) 到 (100,100),定义了一个 100×100 的逻辑画布 -
width="200" height="200":实际渲染成 200×200 像素的物理画布 -
效果:内部 100×100 的图形被等比放大到 200×200,每个逻辑单位 = 2 像素
类比:viewBox 是「地图的经纬度范围」,width/height 是「打印出来的纸张大小」。同一张地图可以印在 A4 上也可以印在 A0 上,清晰度不变——这就是矢量。
| 属性 | 作用 | 示例 |
|---|---|---|
| viewBox | 定义内部坐标系(x, y, width, height) | viewBox="0 0 400 300" |
| width / height | 渲染尺寸(像素或百分比) | width="100%" |
| xmlns | XML 命名空间(必须) | xmlns="http://www.w3.org/2000/svg" |
四、基础形状
SVG 内置了 6 种基本形状,掌握这些就能画 80% 的图形。
4.1 矩形 rect
<rect x="10" y="10" width="80" height="50"
rx="10" ry="10"
fill="#4A90D9" stroke="#2C3E50" stroke-width="2" />
| 属性 | 含义 |
|---|---|
| x, y | 左上角坐标 |
| width, height | 宽高 |
| rx, ry | 圆角半径(类似 CSS 的 border-radius) |
4.2 圆形 circle
<circle cx="50" cy="50" r="40" fill="none" stroke="red" stroke-width="3" />
| 属性 | 含义 |
|---|---|
| cx, cy | 圆心坐标 |
| r | 半径 |
4.3 椭圆 ellipse
<ellipse cx="50" cy="50" rx="40" ry="20" fill="lightgreen" />
rx 和 ry 分别是水平半径和垂直半径,不等就是椭圆。
4.4 直线 line
<line x1="0" y1="0" x2="100" y2="100" stroke="black" stroke-width="2" />
从 (x1,y1) 到 (x2,y2) 画一条线。直线没有 fill,只有 stroke。
4.5 折线 polyline
<polyline points="0,0 50,50 100,0 150,50" fill="none" stroke="blue" />
points 是一组坐标对,用空格分隔。画出的是连续线段,不自动闭合。
4.6 多边形 polygon
<polygon points="50,0 100,100 0,100" fill="yellow" stroke="black" />
和 polyline 类似,但自动闭合(最后一个点和第一个点连起来)。上面这个画了一个三角形。
五、Path 路径 —— SVG 的核心
<path> 是 SVG 中最强大的元素,能画任意形状。所有基础形状都可以用 path 实现,但 path 能做的远不止于此。
5.1 基本语法
<path d="M 10 10 L 90 10 L 90 90 Z" fill="none" stroke="black" />
d 属性是一串「命令 + 参数」的序列,就像给画笔下达指令:
| 命令 | 含义 | 参数 | 类比 |
|---|---|---|---|
| M | Move To(移动到) | x y | 抬笔移到这个位置 |
| L | Line To(画直线到) | x y | 落笔画直线到这里 |
| H | Horizontal Line(水平线) | x | 只改变 x,y 不变 |
| V | Vertical Line(垂直线) | y | 只改变 y,x 不变 |
| Z | Close Path(闭合) | 无 | 回到起点,闭合路径 |
| C | Cubic Bezier(三次贝塞尔曲线) | x1 y1 x2 y2 x y | 两个控制点 + 终点 |
| Q | Quadratic Bezier(二次贝塞尔曲线) | x1 y1 x y | 一个控制点 + 终点 |
| A | Arc(圆弧) | rx ry rotation large-arc sweep x y | 画一段椭圆弧 |
5.2 画一个三角形
<path d="M 50 10 L 90 90 L 10 90 Z" fill="lightblue" stroke="navy" />
读法:移动到 (50,10) → 画线到 (90,90) → 画线到 (10,90) → 闭合回到起点。
5.3 画曲线(贝塞尔)
<!-- 二次贝塞尔:Q 控制点 终点 -->
<path d="M 0 100 Q 50 0 100 100" fill="none" stroke="red" />
<!-- 三次贝塞尔:C 控制点1 控制点2 终点 -->
<path d="M 0 100 C 30 0 70 0 100 100" fill="none" stroke="blue" />
贝塞尔曲线的直觉:控制点像磁铁,把直线「拉弯」。控制点离线越远,弯曲幅度越大。
5.4 画圆弧
<path d="M 50 50 A 30 30 0 0 1 80 50" fill="none" stroke="green" />
A 命令参数最多,7 个值:
| 参数 | 含义 |
|---|---|
| rx, ry | 椭圆的两个半径 |
| rotation | 椭圆的旋转角度(度) |
| large-arc-flag | 0 = 取小弧,1 = 取大弧 |
| sweep-flag | 0 = 逆时针,1 = 顺时针 |
| x, y | 终点坐标 |
圆弧是 SVG 中最复杂的命令,但在画物理图形(斜面、圆弧轨道)时非常有用。
六、样式与美化
6.1 基础样式属性
| 属性 | 作用 | 示例值 |
|---|---|---|
| fill | 填充颜色 | red / #FF5733 / rgb(255,0,0) |
| fill-opacity | 填充透明度 | 0.5(0~1) |
| stroke | 描边颜色 | black / #333 |
| stroke-width | 描边粗细 | 2(默认 1) |
| stroke-dasharray | 虚线模式 | 5,3(画 5 空 3) |
| stroke-linecap | 线帽样式 | butt / round / square |
| opacity | 整体透明度 | 0.8 |
6.2 用 CSS 写样式
<svg viewBox="0 0 100 100">
<style>
.box { fill: #4A90D9; stroke: #2C3E50; stroke-width: 2; }
.highlight { fill: #FF6B6B; opacity: 0.6; }
</style>
<rect class="box" x="10" y="10" width="30" height="30" />
<rect class="highlight" x="10" y="10" width="30" height="30" />
</svg>
SVG 里可以写 <style> 标签,用法和 HTML 的 CSS 一样。这在需要批量控制样式或实现高亮切换时非常实用。
6.3 渐变
线性渐变:
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="red" />
<stop offset="100%" stop-color="blue" />
</linearGradient>
</defs>
<rect x="0" y="0" width="100" height="50" fill="url(#grad1)" />
径向渐变:
<defs>
<radialGradient id="grad2">
<stop offset="0%" stop-color="yellow" />
<stop offset="100%" stop-color="orange" />
</radialGradient>
</defs>
<circle cx="50" cy="50" r="40" fill="url(#grad2)" />
关键点:渐变定义在 <defs> 里,用 id 命名,使用时 fill="url(#id)" 引用。
七、文本
除了图形,SVG 也可以用 <text> 元素直接绘制文字,常用于坐标标注和图内说明。
<text x="10" y="50" font-size="20" font-family="Arial" fill="black">
Hello SVG
</text>
| 属性 | 含义 |
|---|---|
| x, y | 文字基线的起始位置(注意:y 是基线位置,不是顶部) |
| font-size | 字号 |
| font-family | 字体 |
| text-anchor | 对齐方式:start / middle / end |
| dominant-baseline | 垂直对齐:hanging / middle / alphabetic |
多行文本用 <tspan>:
<text x="10" y="20" font-size="14">
<tspan x="10" dy="0">第一行</tspan>
<tspan x="10" dy="20">第二行</tspan>
</text>
八、分组与复用
8.1 <g> 分组
<g transform="translate(50, 50)">
<circle cx="0" cy="0" r="20" fill="red" />
<rect x="-30" y="-30" width="60" height="60" fill="none" stroke="black" />
</g>
<g> 把多个元素打包成一组,可以统一设置样式、变换、ID。类似于 Photoshop 的「编组」。
8.2 <defs> + <use> 定义与引用
<defs>
<g id="arrow">
<line x1="0" y1="0" x2="40" y2="0" stroke="black" stroke-width="2" />
<polygon points="40,0 35,-3 35,3" fill="black" />
</g>
</defs>
<!-- 复用箭头,放在不同位置 -->
<use href="#arrow" x="10" y="10" />
<use href="#arrow" x="10" y="50" />
<use href="#arrow" x="10" y="90" />
定义一次,引用多次。<defs> 中的内容不会直接渲染,只有被 <use> 引用时才显示。
8.3 <symbol> 可复用符号
<symbol id="icon-star" viewBox="0 0 24 24">
<polygon points="12,2 15,9 22,9 17,14 19,21 12,17 5,21 7,14 2,9 9,9" />
</symbol>
<use href="#icon-star" x="0" y="0" width="24" height="24" fill="gold" />
<use href="#icon-star" x="30" y="0" width="48" height="48" fill="red" />
<symbol> 和 <g> 类似,但自带 viewBox,适合定义可缩放的图标库。
九、变换(Transform)
变换可以作用在单个元素或 <g> 分组上,改变其位置/角度/大小。
| 变换 | 语法 | 含义 |
|---|---|---|
| translate | translate(x, y) | 平移 |
| rotate | rotate(angle, cx, cy) | 绕 (cx,cy) 旋转 angle 度 |
| scale | scale(sx, sy) | 缩放 |
| skewX / skewY | skewX(angle) | 倾斜 |
| matrix | matrix(a,b,c,d,e,f) | 自定义 2D 变换矩阵 |
<!-- 原始矩形 -->
<rect x="0" y="0" width="40" height="20" fill="blue" />
<!-- 平移 + 旋转 45 度 -->
<rect x="0" y="0" width="40" height="20" fill="red"
transform="translate(50, 50) rotate(45)" />
<!-- 放大 2 倍 -->
<rect x="0" y="0" width="40" height="20" fill="green"
transform="translate(100, 50) scale(2)" />
十、高级特性
10.1 裁剪路径 clipPath
<defs>
<clipPath id="clip1">
<circle cx="50" cy="50" r="30" />
</clipPath>
</defs>
<!-- 只显示圆形区域内的矩形 -->
<rect x="0" y="0" width="100" height="100" fill="blue"
clip-path="url(#clip1)" />
裁剪路径就像蒙版,只显示路径内的部分。在物理图形中可以用来:高亮滑块区域、遮挡不需要显示的部分。
10.2 遮罩 mask
<defs>
<mask id="mask1">
<rect x="0" y="0" width="100" height="100" fill="black" />
<circle cx="50" cy="50" r="30" fill="white" />
</mask>
</defs>
<rect x="0" y="0" width="100" height="100" fill="blue"
mask="url(#mask1)" />
mask 和 clipPath 类似,但更灵活:白色 = 完全显示,黑色 = 完全隐藏,灰色 = 半透明。可以实现渐变遮罩效果。
10.3 滤镜 filter
<defs>
<filter id="blur1">
<feGaussianBlur stdDeviation="3" />
</filter>
</defs>
<circle cx="50" cy="50" r="30" fill="red" filter="url(#blur1)" />
滤镜可以实现模糊、阴影、发光等效果。常用滤镜:feGaussianBlur(模糊)、feDropShadow(阴影)、feColorMatrix(颜色矩阵)。
十一、动画
11.1 CSS 动画(推荐)
<svg viewBox="0 0 100 100">
<style>
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.gear { animation: spin 3s linear infinite; transform-origin: 50px 50px; }
</style>
<circle class="gear" cx="50" cy="50" r="20" fill="orange" />
</svg>
11.2 SMIL 动画(SVG 原生)
<circle cx="50" cy="50" r="10" fill="red">
<animate attributeName="r" values="10;30;10" dur="2s" repeatCount="indefinite" />
</circle>
SMIL 通过 <animate> 标签直接在 SVG 元素内定义动画,不需要 CSS。
11.3 高亮动画示例(适合教学场景)
<rect x="10" y="10" width="30" height="30" fill="#4A90D9">
<animate attributeName="fill"
values="#4A90D9;#FF6B6B;#4A90D9"
dur="1s" repeatCount="indefinite" />
</rect>
这个效果就是:矩形颜色在蓝色和红色之间循环闪烁——可以用来做题目讲解时的「高亮提示」。
十二、SVG 在 Web 中的使用方式
画好的 SVG 最终要放进网页,常见有以下四种方式。
12.1 内嵌到 HTML(最灵活)
<body>
<svg viewBox="0 0 100 100" width="200" height="200">
<circle cx="50" cy="50" r="40" fill="steelblue" />
</svg>
</body>
直接写在 HTML 里,SVG 变成 DOM 的一部分,可以用 CSS 和 JS 操作每一个元素。
12.2 作为图片引用
<img src="diagram.svg" alt="物理示意图" />
简单但无法通过 JS 操作内部元素。
12.3 作为背景图
.bg {
background-image: url('pattern.svg');
background-size: cover;
}
12.4 用 JavaScript 动态生成
// 创建一个 SVG 圆形
const svgNS = "http://www.w3.org/2000/svg";
const circle = document.createElementNS(svgNS, "circle");
circle.setAttribute("cx", "50");
circle.setAttribute("cy", "50");
circle.setAttribute("r", "30");
circle.setAttribute("fill", "red");
document.querySelector("svg").appendChild(circle);
// 修改属性实现高亮
circle.setAttribute("fill", "yellow");
circle.setAttribute("stroke", "orange");
circle.setAttribute("stroke-width", "3");
这段代码展示了「用 JS 动态创建和修改 SVG」——这正是你的实习项目中「讲解时实时高亮物理图形元素」的技术基础。
十三、实战案例:物理题示意图
下面用 SVG 画一个「滑块在斜面上滑动」的物理示意图,并演示如何高亮滑块:
<svg viewBox="0 0 300 200" width="100%">
<style>
.highlight { fill: #FF6B6B; stroke: #E74C3C; stroke-width: 2; }
.normal { fill: #BDC3C7; stroke: #7F8C8D; stroke-width: 1; }
</style>
<!-- 地面 -->
<line x1="20" y1="170" x2="280" y2="170" stroke="#333" stroke-width="2" />
<!-- 斜面(三角形) -->
<polygon points="50,170 200,170 200,50" fill="#ECF0F1" stroke="#333" stroke-width="2" />
<!-- 滑块(高亮状态) -->
<rect id="block" class="highlight" x="155" y="52" width="30" height="20"
transform="rotate(-33.7, 170, 62)" />
<!-- 标注文字 -->
<text x="165" y="45" font-size="12" fill="#E74C3C" text-anchor="middle">滑块</text>
<text x="125" y="190" font-size="12" fill="#333" text-anchor="middle">斜面</text>
</svg>
效果说明:斜面用 polygon 画三角形,滑块用 rect + rotate 旋转贴合斜面角度,通过 CSS class 切换实现高亮/取消高亮。
用 JS 控制高亮的代码:
// 高亮滑块
document.getElementById("block").setAttribute("class", "highlight");
// 取消高亮
document.getElementById("block").setAttribute("class", "normal");
十四、速查表
最后把前面出现过的元素、Path 命令和样式属性汇总成表,方便随手查阅。
常用元素
| 元素 | 用途 | 核心属性 |
|---|---|---|
| rect | 矩形 | x y width height rx |
| 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 | 分组 | transform |
| use | 引用复用 | href x y |
| defs | 定义(不渲染) | — |
| linearGradient | 线性渐变 | x1 y1 x2 y2 |
| radialGradient | 径向渐变 | cx cy r |
| clipPath | 裁剪路径 | — |
| mask | 遮罩 | — |
| filter | 滤镜 | — |
Path 命令速查
| 命令 | 含义 | 示例 |
|---|---|---|
| M / m | 移动到 | M 10 10 |
| L / l | 直线到 | L 90 10 |
| H / h | 水平线 | H 90 |
| V / v | 垂直线 | V 90 |
| Z / z | 闭合路径 | Z |
| C / c | 三次贝塞尔 | C 20 0 80 0 100 50 |
| Q / q | 二次贝塞尔 | Q 50 0 100 50 |
| A / a | 圆弧 | A 30 30 0 0 1 80 50 |
常用样式属性
| 属性 | 作用 | 常用值 |
|---|---|---|
| fill | 填充色 | 颜色名 / hex / rgb / none |
| stroke | 描边色 | 颜色名 / hex / none |
| stroke-width | 描边粗细 | 数字 |
| stroke-dasharray | 虚线 | 5,3 |
| opacity | 透明度 | 0~1 |
| transform | 变换 | translate/rotate/scale |
(注:部分内容可能由 AI 生成)