SVG 路径(path)
SVG 的 <path> 元素是最强大的图形元素,通过 d 属性中的指令可以绘制任意复杂的二维图形。路径指令包括移动、画线、弧线、贝塞尔曲线等,是 SVG 图形表达的核心。本节将详细介绍 d 属性中各种指令的用法和组合技巧。
前置知识
阅读本节前,建议先了解:SVG 基本图形
基础概念
<path> 的 d 属性是一系列绘图指令的集合。每条指令由一个命令字母和随后的参数组成。命令分为绝对坐标(大写字母)和相对坐标(小写字母)两种形式。
指令分类
| 类别 | 指令 | 说明 |
|---|---|---|
| 移动 | M / m | 移动到指定点 |
| 直线 | L / l | 画直线到指定点 |
| 水平线 | H / h | 画水平线 |
| 垂直线 | V / v | 画垂直线 |
| 三次贝塞尔 | C / c | 三次贝塞尔曲线 |
| 简写三次贝塞尔 | S / s | 平滑三次贝塞尔 |
| 二次贝塞尔 | Q / q | 二次贝塞尔曲线 |
| 简写二次贝塞尔 | T / t | 平滑二次贝塞尔 |
| 弧线 | A / a | 椭圆弧 |
| 闭合 | Z / z | 闭合路径 |
详细说明
M - 移动(Move To)
M x,y 或 m dx,dy 移动画笔到指定位置,不画线。
html
<!-- 绝对移动 -->
<path d="M 50,50 L 200,50" stroke="#4285f4" stroke-width="2" fill="none"/>
<!-- 相对移动 -->
<path d="M 50,100 m 50,0 L 200,100" stroke="#34a853" stroke-width="2" fill="none"/>
<!-- m 50,0 表示从当前位置向右移动 50 -->L - 直线(Line To)
html
<!-- 绘制三角形 -->
<path d="M 100,20 L 180,160 L 20,160 Z"
fill="#4285f4" stroke="#333" stroke-width="2"/>
<!-- 多条连续直线 -->
<path d="M 20,20 L 80,20 L 80,80 L 20,80 Z"
fill="#ea4335" stroke="none"/>H - 水平线 / V - 垂直线
html
<!-- H:水平线到指定 X -->
<path d="M 20,50 H 200" stroke="#4285f4" stroke-width="2" fill="none"/>
<!-- V:垂直线到指定 Y -->
<path d="M 100,20 V 150" stroke="#34a853" stroke-width="2" fill="none"/>
<!-- 组合:阶梯形 -->
<path d="M 20,150 H 60 V 100 H 100 V 50 H 140 V 20"
stroke="#ea4335" stroke-width="2" fill="none" stroke-linejoin="round"/>C - 三次贝塞尔曲线
C cp1x,cp1y cp2x,cp2y x,y 使用两个控制点绘制三次贝塞尔曲线。
html
<path d="M 20,200 C 100,50 200,350 380,200"
stroke="#4285f4" stroke-width="2" fill="none"/>
<!-- 带控制点辅助线的可视化 -->
<svg width="400" height="250" viewBox="0 0 400 250">
<!-- 曲线 -->
<path d="M 20,200 C 100,50 200,350 380,200"
stroke="#4285f4" stroke-width="2" fill="none"/>
<!-- 控制点辅助线 -->
<line x1="20" y1="200" x2="100" y2="50" stroke="#ccc" stroke-dasharray="5,5"/>
<line x1="100" y1="50" x2="200" y2="350" stroke="#ccc" stroke-dasharray="5,5"/>
<line x1="200" y1="350" x2="380" y2="200" stroke="#ccc" stroke-dasharray="5,5"/>
<!-- 控制点 -->
<circle cx="20" cy="200" r="4" fill="#ea4335"/>
<circle cx="100" cy="50" r="4" fill="#fbbc05"/>
<circle cx="200" cy="350" r="4" fill="#fbbc05"/>
<circle cx="380" cy="200" r="4" fill="#ea4335"/>
</svg>S - 平滑三次贝塞尔
S cp2x,cp2y x,y 是三次贝塞尔的简写形式,第一个控制点自动从前一条曲线的第二个控制点反射得到。
html
<!-- 两条连续的三次贝塞尔 -->
<path d="M 20,200 C 80,50 150,50 200,200 S 320,350 380,200"
stroke="#4285f4" stroke-width="2" fill="none"/>Q - 二次贝塞尔曲线
Q cpx,cpy x,y 使用一个控制点绘制二次贝塞尔曲线。
html
<path d="M 20,200 Q 200,20 380,200"
stroke="#34a853" stroke-width="2" fill="none"/>
<!-- 控制点辅助线 -->
<line x1="20" y1="200" x2="200" y2="20" stroke="#ccc" stroke-dasharray="5,5"/>
<line x1="200" y1="20" x2="380" y2="200" stroke="#ccc" stroke-dasharray="5,5"/>
<circle cx="200" cy="20" r="4" fill="#ea4335"/>T - 平滑二次贝塞尔
T x,y 是二次贝塞尔的简写形式,控制点自动反射。
html
<path d="M 20,200 Q 100,20 200,200 T 380,200"
stroke="#9c27b0" stroke-width="2" fill="none"/>A - 椭圆弧
A rx ry x-rotation large-arc-flag sweep-flag x,y 绘制椭圆弧。
html
<!-- A 的参数说明 -->
<!--
rx, ry: 椭圆半径
x-rotation: 椭圆旋转角度
large-arc-flag: 0(小弧)或 1(大弧)
sweep-flag: 0(逆时针)或 1(顺时针)
x, y: 终点坐标
-->
<!-- 绘制半圆弧 -->
<path d="M 50,150 A 100,100 0 0 1 250,150"
stroke="#4285f4" stroke-width="2" fill="none"/>
<!-- 大弧 vs 小弧 -->
<path d="M 50,100 A 80,80 0 0 0 250,100"
stroke="#34a853" stroke-width="2" fill="none"/> <!-- 小弧 -->
<path d="M 50,100 A 80,80 0 1 0 250,100"
stroke="#ea4335" stroke-width="2" fill="none" stroke-dasharray="5,5"/> <!-- 大弧 -->
<!-- 顺时针 vs 逆时针 -->
<path d="M 150,20 A 80,80 0 0 1 230,100"
stroke="#9c27b0" stroke-width="2" fill="none"/> <!-- 顺时针 -->
<path d="M 150,20 A 80,80 0 0 0 230,100"
stroke="#fbbc05" stroke-width="2" fill="none"/> <!-- 逆时针 -->Z - 闭合路径
Z 或 z 从当前点画直线到路径起点,闭合路径。
html
<!-- 闭合路径 -->
<path d="M 100,20 L 180,160 L 20,160 Z"
fill="#4285f4" fill-opacity="0.3" stroke="#4285f4" stroke-width="2"/>贝塞尔曲线对比
| 曲线类型 | 指令 | 控制点 | 灵活度 | 适用场景 |
|---|---|---|---|---|
| 三次贝塞尔 | C | 2 个 | 高 | S 形曲线、复杂形状 |
| 平滑三次 | S | 1 个(自动反射) | 中高 | 平滑连接 |
| 二次贝塞尔 | Q | 1 个 | 中 | 简单曲线 |
| 平滑二次 | T | 0 个(自动反射) | 中 | 连续平滑曲线 |
实战示例
示例 1:常见图形用 path 绘制
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>SVG 路径图形</title>
<style>
svg { border: 1px solid #ccc; display: block; margin: 10px 0; }
</style>
</head>
<body>
<h1>SVG 路径绘制常见图形</h1>
<svg width="600" height="400" viewBox="0 0 600 400">
<!-- 心形 -->
<path d="M 100,180
C 100,140 60,100 30,100
C -10,100 -10,150 30,190
L 100,250
L 170,190
C 210,150 210,100 170,100
C 140,100 100,140 100,180 Z"
fill="#ea4335"/>
<!-- 星形 -->
<path d="M 300,30 L 315,100 L 385,100 L 330,145 L 350,215 L 300,175 L 250,215 L 270,145 L 215,100 L 285,100 Z"
fill="#fbbc05" stroke="#ea4335" stroke-width="1"/>
<!-- 箭头 -->
<path d="M 420,50 L 560,130 L 420,210 M 460,130 L 560,130"
stroke="#4285f4" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<!-- 云朵 -->
<path d="M 400,350
a 30,30 0 0 1 50,-10
a 40,40 0 0 1 70,0
a 30,30 0 0 1 50,10
Z"
fill="#90caf9" stroke="#4285f4" stroke-width="1"/>
<!-- 标签 -->
<text x="70" y="280" font-size="12" fill="#333">心形</text>
<text x="280" y="250" font-size="12" fill="#333">星形</text>
<text x="450" y="250" font-size="12" fill="#333">箭头</text>
</svg>
</body>
</html>示例 2:波浪线
html
<svg width="400" height="100" viewBox="0 0 400 100">
<!-- 正弦波 -->
<path d="M 0,50 Q 50,0 100,50 T 200,50 T 300,50 T 400,50"
stroke="#4285f4" stroke-width="2" fill="none"/>
<!-- 更密集的波浪 -->
<path d="M 0,80 Q 25,60 50,80 T 100,80 T 150,80 T 200,80 T 250,80 T 300,80 T 350,80 T 400,80"
stroke="#34a853" stroke-width="1.5" fill="none"/>
</svg>示例 3:图表中的路径
html
<!-- 面积图 -->
<svg width="400" height="200" viewBox="0 0 400 200">
<defs>
<linearGradient id="areaGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#4285f4" stop-opacity="0.5"/>
<stop offset="100%" stop-color="#4285f4" stop-opacity="0.1"/>
</linearGradient>
</defs>
<!-- 填充区域 -->
<path d="M 0,180 L 40,140 C 60,120 80,100 120,110
S 180,80 200,60 S 240,100 280,90
S 340,50 360,40 L 400,30 L 400,200 L 0,200 Z"
fill="url(#areaGrad)"/>
<!-- 线条 -->
<path d="M 0,180 L 40,140 C 60,120 80,100 120,110
S 180,80 200,60 S 240,100 280,90
S 340,50 360,40 L 400,30"
stroke="#4285f4" stroke-width="2" fill="none"/>
<!-- 数据点 -->
<circle cx="0" cy="180" r="3" fill="#4285f4"/>
<circle cx="40" cy="140" r="3" fill="#4285f4"/>
<circle cx="120" cy="110" r="3" fill="#4285f4"/>
<circle cx="200" cy="60" r="3" fill="#4285f4"/>
<circle cx="280" cy="90" r="3" fill="#4285f4"/>
<circle cx="360" cy="40" r="3" fill="#4285f4"/>
</svg>注意事项
1. 指令参数分隔
html
<!-- 正确:逗号或空格分隔 -->
<path d="M 10,10 L 100,100"/>
<path d="M10 10 L100 100"/>
<path d="M10,10 L100,100"/>
<!-- 也可以混合使用 -->
<path d="M 10 10, L 100,100"/>2. 省略重复指令
html
<!-- M 后的多个坐标隐含 L 指令 -->
<path d="M 10,10 100,10 100,100 10,100 Z"/>
<!-- 等价于 -->
<path d="M 10,10 L 100,10 L 100,100 L 10,100 Z"/>3. 弧线指令的常见问题
html
<!-- 弧线半径不能为 0 -->
<path d="M 0,0 A 0,0 0 0 1 100,100"/> <!-- 错误! -->
<!-- 终点不能与起点相同(需要用弧线闭合用 Z) -->最佳实践
1. 使用工具生成路径
复杂路径通常由设计工具(Figma、Illustrator、Inkscape)导出,手动编写容易出错。
2. 路径简化技巧
html
<!-- 复杂:多个 M 指令 -->
<path d="M 10,10 L 50,10 M 10,30 L 50,30 M 10,50 L 50,50"/>
<!-- 简化:合并到同一路径(用 M 划分子路径) -->
<path d="M 10,10 h 40 M 10,30 h 40 M 10,50 h 40"/>
<!-- 用 CSS 控制样式 -->
<style>
.line-group path { stroke: #4285f4; stroke-width: 2; fill: none; }
</style>
<g class="line-group">
<path d="M 10,10 h 40 M 10,30 h 40 M 10,50 h 40"/>
</g>3. pathLength 属性(动画利器)
html
<!-- pathLength 可以让路径长度标准化为 1 -->
<svg width="200" height="100" viewBox="0 0 200 100">
<path d="M 10,50 Q 100,0 190,50"
stroke="#4285f4" stroke-width="3" fill="none"
stroke-dasharray="1" stroke-dashoffset="1"
pathLength="1">
<animate attributeName="stroke-dashoffset" from="1" to="0" dur="2s" fill="freeze"/>
</path>
</svg>下一节
继续学习:SVG 渐变与滤镜