深入 SVG:矢量图形、滤镜与动态交互开发指南
1.SVG 详细介绍
SVG(Scalable Vector Graphics) 是一种基于 XML 的矢量图形格式,用于描述二维图形。
1. 命名空间 (Namespace)
-
命名空间 URI:
http://www.w3.org/2000/svg
-
用途:在 XML 或 XHTML 中区分不同标记语言的元素。
-
声明方式:
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"><!-- SVG 内容 --> </svg>
2. SVG API
-
DOM API:通过 JavaScript 操作 SVG 元素。
-
创建元素:
document.createElementNS(namespaceURI, tagName)
-
示例:
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", "100"); svg.setAttribute("height", "100"); document.body.appendChild(svg);
-
-
SVG DOM 接口:如
SVGElement
,SVGRectElement
,SVGPathElement
等,提供特定元素的属性和方法。 -
动画 API:支持 SMIL(已部分弃用)、CSS 动画或 JavaScript 动画库(如 GSAP)。
3. 常用 SVG 代码示例
示例 3.1 - 基本形状
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SVG 基本形状</title>
</head>
<body><svg width="400" height="300"><!-- 矩形 --><rect x="10" y="10" width="50" height="30" fill="blue" stroke="black" stroke-width="2"/><!-- 圆形 --><circle cx="100" cy="50" r="30" fill="red"/><!-- 椭圆 --><ellipse cx="200" cy="50" rx="40" ry="20" fill="green"/><!-- 线条 --><line x1="10" y1="100" x2="150" y2="100" stroke="purple" stroke-width="3"/><!-- 折线 --><polyline points="10,150 50,120 90,180" fill="none" stroke="orange"/><!-- 多边形 --><polygon points="200,150 250,120 300,180" fill="yellow" stroke="brown"/></svg>
</body>
</html>
示例 3.2 - 路径(Path)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SVG 路径</title>
</head>
<body><svg width="200" height="200"><path d="M10 80 Q 100 10 190 80 T 370 80"fill="none" stroke="black" stroke-width="2"/></svg>
</body>
</html>
示例 3.3 - 文本
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SVG 文本</title>
</head>
<body><svg width="300" height="100"><text x="20" y="30" font-family="Arial" font-size="20" fill="navy">SVG 文本示例</text></svg>
</body>
</html>
示例 3.4 - 渐变与图案
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SVG 渐变与图案</title>
</head>
<body><svg width="200" height="200"><defs><linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stop-color="#ff0000"/><stop offset="100%" stop-color="#0000ff"/></linearGradient><pattern id="pattern1" width="20" height="20" patternUnits="userSpaceOnUse"><rect width="10" height="10" fill="#00ff00"/></pattern></defs><rect x="10" y="10" width="100" height="100" fill="url(#grad1)"/><circle cx="150" cy="150" r="30" fill="url(#pattern1)"/></svg>
</body>
</html>
示例 3.5 - 滤镜效果
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SVG 滤镜</title>
</head>
<body><svg width="200" height="200"><defs><filter id="blur"><feGaussianBlur in="SourceGraphic" stdDeviation="5"/></filter><filter id="shadow"><feDropShadow dx="5" dy="5" stdDeviation="3" flood-color="rgba(0,0,0,0.5)"/></filter></defs><rect x="20" y="20" width="100" height="100" fill="teal" filter="url(#shadow)"/><circle cx="150" cy="150" r="30" fill="red" filter="url(#blur)"/></svg>
</body>
</html>
示例 3.6 - 动画
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SVG 动画</title><style>.pulse {animation: pulse 1s infinite;}@keyframes pulse {0% { r: 10; }50% { r: 20; }100% { r: 10; }}</style>
</head>
<body><!-- SMIL 动画(部分浏览器已弃用) --><svg width="200" height="200"><circle cx="50" cy="50" r="20" fill="blue"><animate attributeName="cx" from="50" to="150" dur="2s" repeatCount="indefinite"/></circle></svg><!-- CSS 动画 --><svg width="200" height="200"><circle class="pulse" cx="100" cy="100" r="10" fill="green"/></svg>
</body>
</html>
示例 3.7 - 交互性(JavaScript)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SVG 交互</title>
</head>
<body><svg width="200" height="200"><rect id="btn" x="50" y="50" width="100" height="50" fill="gray"/><script>document.getElementById('btn').addEventListener('click', function() {this.setAttribute('fill', '#' + Math.floor(Math.random()*16777215).toString(16));});</script></svg>
</body>
</html>
示例 3.8 - 视口与 viewBox
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SVG 视口</title>
</head>
<body><svg width="200" height="200" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet"><circle cx="50" cy="50" r="40" fill="orange"/></svg>
</body>
</html>
示例 3.9 - 复用元素
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SVG 复用元素</title>
</head>
<body><svg width="300" height="100"><defs><symbol id="icon" viewBox="0 0 24 24"><path d="M12 2L3 9v12h18V9l-9-7z"/></symbol></defs><use href="#icon" x="10" y="10" width="30" height="30" fill="purple"/><use href="#icon" x="100" y="10" width="30" height="30" fill="pink"/></svg>
</body>
</html>
4.SVG 中常见图形元素的属性总结
1. 矩形 <rect>
属性列表:
属性 | 含义 | 示例值 |
---|---|---|
x | 矩形左上角的 x 坐标 | "10" |
y | 矩形左上角的 y 坐标 | "10" |
width | 矩形的宽度 | "50" |
height | 矩形的高度 | "30" |
rx | 圆角矩形的水平圆角半径(可选) | "5" |
ry | 圆角矩形的垂直圆角半径(可选) | "5" |
fill | 填充颜色 | "blue" , "#00FF00" |
stroke | 边框颜色 | "black" |
stroke-width | 边框宽度 | "2" |
stroke-dasharray | 虚线边框样式(如 "5,3" 表示 5px 实线 + 3px 空白) | "5,3" |
opacity | 透明度(0-1) | "0.5" |
<rect x="10" y="10" width="50" height="30" rx="5" fill="blue" stroke="black" stroke-width="2"/>
2. 圆形 <circle>
属性 | 含义 | 示例值 |
---|---|---|
cx | 圆心的 x 坐标 | "100" |
cy | 圆心的 y 坐标 | "50" |
r | 圆的半径 | "30" |
fill | 填充颜色 | "red" |
stroke | 边框颜色(同 <rect> ) | "black" |
示例:
<circle cx="100" cy="50" r="30" fill="red"/>
3. 椭圆 <ellipse>
属性 | 含义 | 示例值 |
---|---|---|
cx | 椭圆中心的 x 坐标 | "200" |
cy | 椭圆中心的 y 坐标 | "50" |
rx | 水平半径 | "40" |
ry | 垂直半径 | "20" |
fill | 填充颜色 | "green" |
示例:
<ellipse cx="200" cy="50" rx="40" ry="20" fill="green"/>
4. 线条 <line>
属性 | 含义 | 示例值 |
---|---|---|
x1 , y1 | 起点坐标 | "10" , "100" |
x2 , y2 | 终点坐标 | "150" , "100" |
stroke | 线条颜色(必须设置) | "purple" |
stroke-width | 线条宽度 | "3" |
示例:
<line x1="10" y1="100" x2="150" y2="100" stroke="purple" stroke-width="3"/>
5. 折线 <polyline>
属性 | 含义 | 示例值 |
---|---|---|
points | 一系列坐标点(格式:x1,y1 x2,y2... ) | "10,150 50,120 90,180" |
fill | 填充颜色(通常设为 "none" ) | "none" |
stroke | 线条颜色 | "orange" |
示例:
<polyline points="10,150 50,120 90,180" fill="none" stroke="orange"/>
6. 多边形 <polygon>
属性 | 含义 | 示例值 |
---|---|---|
points | 闭合路径的坐标点(同 <polyline> ) | "200,150 250,120 300,180" |
fill | 填充颜色 | "yellow" |
stroke | 边框颜色 | "brown" |
示例:
<polygon points="200,150 250,120 300,180" fill="yellow" stroke="brown"/>
7. 路径 <path>
属性 | 含义 | 示例值 |
---|---|---|
d | 路径指令(见下方说明) | "M10 80 Q 100 10 190 80" |
fill | 填充颜色("none" 表示不填充) | "none" |
stroke | 路径线条颜色 | "black" |
路径指令(d
属性):
-
M x,y
:移动到 (x,y) -
L x,y
:画线到 (x,y) -
Q x1,y1 x,y
:二次贝塞尔曲线 -
Z
:闭合路径
示例:
<path d="M10 80 Q 100 10 190 80 T 370 80" fill="none" stroke="black"/>
8. 文本 <text>
属性 | 含义 | 示例值 |
---|---|---|
x , y | 文本基线起点坐标 | "20" , "30" |
font-family | 字体 | "Arial" |
font-size | 字体大小 | "20" |
fill | 文本颜色 | "navy" |
text-anchor | 文本对齐(start /middle /end ) | "middle" |
示例:
<text x="20" y="30" font-family="Arial" font-size="20" fill="navy">SVG Text</text>
9.通用属性
所有图形元素均可使用以下属性:
属性 | 含义 |
---|---|
fill | 填充颜色(支持颜色名、HEX、RGB等) |
stroke | 边框颜色 |
stroke-width | 边框宽度 |
opacity | 整体透明度(0-1) |
transform | 变换(如 rotate(45) 、scale(2) ) |
10.属性总结
-
基本图形:
<rect>
,<circle>
,<ellipse>
,<line>
,<polyline>
,<polygon>
。 -
高级路径:
<path>
通过指令实现任意形状。 -
文本:
<text>
支持样式和定位。 -
通用样式:
fill
,stroke
,opacity
等可跨元素复用。
5.使用 SVG 绘制的移动端常见返回按钮
方案 1:直接使用 <path>
绘制
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SVG 返回按钮</title><style>body {display: flex;justify-content: center;align-items: center;height: 100vh;margin: 0;}.back-button {width: 40px;height: 40px;cursor: pointer;}.back-button:hover path {fill: #007AFF; /* 悬停时变色 */}</style>
</head>
<body><!-- 返回按钮 SVG --><svg class="back-button" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"fill="#000000" <!-- 默认黑色 -->stroke="none"/></svg>
</body>
</html>
关键点说明:
-
路径 (
d
属性):-
M20 11
:移动到起点 (20, 11)。 -
H7.83
:水平画线到 x=7.83。 -
l5.59-5.59
:相对绘制斜线(箭头头部)。 -
L12 4
:绝对坐标画线到 (12, 4)。 -
l-8 8 8 8
:绘制箭头尾部两段线。 -
1.41-1.41
:调整箭头头部细节。 -
H20v-2z
:闭合路径。
-
-
交互效果:
-
通过 CSS 悬停 (
:hover
) 改变颜色。 -
cursor: pointer
表示可点击。
-
方案 2:使用 <symbol>
复用(适合多个按钮)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SVG 复用返回按钮</title><style>body {display: flex;gap: 20px;justify-content: center;align-items: center;height: 100vh;margin: 0;}.back-button {width: 40px;height: 40px;cursor: pointer;}.back-button:hover use {fill: #FF3B30; /* 悬停红色 */}</style>
</head>
<body><!-- 定义符号 --><svg style="display: none;"><symbol id="back-arrow" viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></symbol></svg><!-- 复用按钮 --><svg class="back-button"><use href="#back-arrow" fill="#000000"/></svg><svg class="back-button"><use href="#back-arrow" fill="#007AFF"/></svg>
</body>
</html>
优势:
-
复用性:通过
<symbol>
定义一次,多处通过<use>
引用。 -
灵活样式:每个实例可独立设置颜色/大小。
方案3:其他变体(简洁箭头)
如果需要一个更简单的箭头样式,可以修改 d
属性:
<path d="M15 18l-6-6 6-6" fill="none" stroke="#000" stroke-width="2"/>
效果:←
样式的细线箭头。
6.SVG 和 Canvas 的区别
SVG 和 Canvas 是两种完全不同的网页图形技术,它们在实现方式、适用场景和性能特点上有显著差异。以下是它们的核心区别:
1. 基础概念
特性 | SVG | Canvas |
---|---|---|
类型 | 矢量图形(基于 XML) | 位图(基于 JavaScript API) |
渲染方式 | 保留模式(Retained Mode) | 立即模式(Immediate Mode) |
DOM 支持 | 是(每个图形是 DOM 元素) | 否(只是一个画布像素区) |
分辨率无关 | 是(无限缩放不失真) | 否(放大后像素化) |
2. 技术细节对比
SVG
工作原理:
通过 XML 描述图形,浏览器解析后生成可操作的 DOM 节点。
<svg width="100" height="100"><circle cx="50" cy="50" r="40" fill="red"/>
</svg>
-
特点:
-
支持 CSS 样式和动画。
-
内置事件处理(如
onclick
)。 -
适合静态或交互复杂的图形(如图标、图表)。
-
Canvas
工作原理:
通过 JavaScript 动态绘制像素,无持久化对象。
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(50, 50, 40, 0, Math.PI * 2);
ctx.fill();
-
特点:
-
高性能,适合频繁重绘(如游戏、动态数据可视化)。
-
需要手动管理状态和重绘。
-
无内置事件系统,需通过数学计算实现交互。
-
3. 性能与适用场景
场景 | SVG | Canvas |
---|---|---|
图形复杂度 | 适合少量复杂图形(如矢量图标) | 适合大量简单图形(如粒子效果) |
动态更新频率 | 低(DOM 操作成本高) | 高(直接操作像素) |
交互需求 | 内置事件支持(如点击、悬停) | 需手动计算交互区域 |
动画 | CSS/SMIL 动画或 JS 控制属性 | 必须通过 JS 逐帧重绘 |
典型应用 | 地图、UI 图标、可缩放图表 | 游戏、实时数据可视化、图像处理 |
4. 代码示例对比
绘制一个可点击的圆形
SVG 实现(自带事件):
<svg width="100" height="100"><circle cx="50" cy="50" r="40" fill="red" onclick="alert('Clicked!')"/>
</svg>
Canvas 实现(需手动检测点击):
<canvas id="canvas" width="100" height="100"></canvas>
<script>const canvas = document.getElementById('canvas');const ctx = canvas.getContext('2d');// 绘制圆ctx.fillStyle = 'red';ctx.beginPath();ctx.arc(50, 50, 40, 0, Math.PI * 2);ctx.fill();// 手动检测点击canvas.addEventListener('click', (e) => {const x = e.offsetX, y = e.offsetY;const distance = Math.sqrt((x - 50) ** 2 + (y - 50) ** 2);if (distance <= 40) alert('Clicked!');});
</script>
5. 选择建议
-
用 SVG 如果:
-
需要矢量缩放(如响应式设计)。
-
图形需要单独交互或动画。
-
图形数量较少(避免 DOM 性能问题)。
-
-
用 Canvas 如果:
-
需要高性能渲染(如 60fps 动画)。
-
处理像素级操作(如滤镜、图像分析)。
-
图形数量极多(如上万元素的可视化)。
-
6. 进阶对比
高级功能 | SVG | Canvas |
---|---|---|
文本渲染 | 完美支持(可选中、样式丰富) | 基础支持(需手动处理换行等) |
图像处理 | 有限(通过 <image> 标签) | 强大(像素操作、WebGL 扩展) |
内存占用 | 较高(DOM 节点开销) | 较低(纯像素缓冲区) |
学习曲线 | 简单(声明式语法) | 较陡(需理解绘图 API) |
7.总结
-
SVG 是声明式的矢量图形,适合交互复杂、需要缩放的场景。
-
Canvas 是命令式的位图绘制,适合高性能、动态渲染的场景。
根据项目需求混合使用两者(例如用 SVG 做 UI,Canvas 渲染背景动画)往往是最佳实践。
7.SVG兼容问题汇总
1. 浏览器兼容性问题
1.1 旧版浏览器(IE 8 及以下)
-
问题:
-
IE 8 及更早版本完全不支持 SVG。
-
IE 9-11 部分支持,但存在 Bug(如滤镜效果、CSS 动画)。
-
-
解决方案:
-
使用 Polyfill(如 SVG for Everybody)或转换为 PNG 备用。
-
通过
<img>
引入 SVG 时,添加onerror
回退:<img src="image.svg" onerror="this.src='fallback.png'" />
-
1.2 Android 4.3 及以下
-
问题:
-
部分 SVG 特性(如
viewport
、transform
)支持不完整。
-
-
解决方案:
-
避免复杂变换,使用简化 SVG 代码。
-
2. 功能兼容性问题
2.1 SVG 滤镜(<filter>
)
-
问题:
-
部分浏览器(如旧版 Firefox)对
feBlend
、feColorMatrix
等滤镜效果支持不完整。
-
-
解决方案:
-
使用 CSS 滤镜(如
filter: blur(5px)
)作为备用。 -
测试效果并简化滤镜链。
-
2.2 SVG 动画
-
问题:
-
SMIL 动画(如
<animate>
)在 Chrome 45+ 已弃用,但部分浏览器仍支持。 -
CSS 动画对
transform
属性的支持不一致。
-
-
解决方案:
-
改用 CSS 动画或 JavaScript 动画库(如 GSAP、Snap.svg)。
-
检测 SMIL 支持并回退:
if (!document.createElementNS('http://www.w3.org/2000/svg', 'animate').toString().includes('SVGAnimateElement')) {console.log('SMIL 不支持'); }
-
2.3 字体与文本
-
问题:
-
<text>
元素在跨平台渲染时可能出现字体不一致或换行错误。
-
-
解决方案:
-
使用
textPath
或手动换行(<tspan>
)。 -
将文本转换为路径(设计工具中操作)。
-
3. 嵌入方式的兼容性
3.1 <img>
标签引入 SVG
-
问题:
-
无法通过 CSS 修改 SVG 内部样式。
-
部分浏览器禁用 SVG 内联脚本。
-
-
解决方案:
-
改用
<object>
或内联 SVG:<object data="image.svg" type="image/svg+xml"></object>
-
3.2 CSS 背景图
-
问题:
-
旧版 iOS Safari 可能无法正确缩放 SVG 背景。
-
-
解决方案:
-
显式设置
background-size
:.element {background: url('image.svg');background-size: 100% 100%; }
-
4. 交互与脚本问题
4.1 事件绑定
-
问题:
-
动态创建的 SVG 元素在旧版 Android 中可能无法触发事件。
-
-
解决方案:
-
使用事件委托(委托到父级 SVG 或 HTML 元素)。
-
4.2 动态修改 SVG
-
问题:
-
直接修改
d
属性(如<path>
)在 IE 中可能不触发重绘。
-
-
解决方案:
-
强制重绘:
path.setAttribute('d', newValue); path.style.transform = 'scale(1)'; // 触发重绘
-
5. 其他常见问题
5.1 尺寸与视口
-
问题:
-
未设置
viewBox
时,某些浏览器可能无法正确缩放 SVG。
-
-
解决方案:
-
始终显式定义
viewBox
和width
/height
:<svg width="100" height="100" viewBox="0 0 100 100">...</svg>
-
5.2 外链资源
-
问题:
-
外部 SVG 文件中的
<use href="external.svg#icon">
在 Firefox 中可能受限。
-
-
解决方案:
-
使用内联 SVG 或工具链(如 Webpack)将 SVG 打包为数据 URI。
-
svg兼容性总结
-
主要问题:旧版浏览器(IE/旧移动端)、滤镜/动画支持、动态交互。
-
检测函数:
// Can I Use 也可以直接看 if (Modernizr.svg) {console.log('SVG 支持'); }
-
通用建议:
-
优先使用内联 SVG 以最大化控制权。
-
复杂场景提供 PNG 回退。
-
测试目标平台的关键功能(如动画、滤镜)。
-
通过预处理工具(如 SVGO 优化代码)和渐进增强策略,可以显著降低 SVG 的兼容性风险。