SVG (Scalable Vector Graphics)
什么是SVG
SVG是一种基于XML的矢量图形格式,用于描述二维图形和图形应用程序。与栅格图像(如JPEG、PNG)不同,SVG图像是由数学公式定义的,因此可以无限缩放而不会失去质量。
基本结构
svg
<svg version="1.1"
baseProfile="full"
width="300" height="200"
xmlns="http://www.w3.org/2000/svg">
<!-- 图形内容 -->
</svg><svg version="1.1"
baseProfile="full"
width="300" height="200"
xmlns="http://www.w3.org/2000/svg">
<!-- 图形内容 -->
</svg>根元素属性
width和height:设置SVG画布的尺寸viewBox:定义SVG的坐标系和可见区域svg<svg viewBox="0 0 300 200" width="300" height="200"><svg viewBox="0 0 300 200" width="300" height="200">xmlns:指定SVG命名空间,必须为http://www.w3.org/2000/svg
基本形状
矩形 (rect)
svg
<rect x="50" y="50" width="200" height="100"
fill="blue" stroke="red" stroke-width="2"
rx="10" ry="10" /><rect x="50" y="50" width="200" height="100"
fill="blue" stroke="red" stroke-width="2"
rx="10" ry="10" />x,y:矩形左上角坐标width,height:矩形尺寸rx,ry:圆角半径
圆形 (circle)
svg
<circle cx="150" cy="100" r="80"
fill="green" stroke="black" stroke-width="3" /><circle cx="150" cy="100" r="80"
fill="green" stroke="black" stroke-width="3" />cx,cy:圆心坐标r:半径
椭圆 (ellipse)
svg
<ellipse cx="150" cy="100" rx="100" ry="50"
fill="purple" stroke="yellow" stroke-width="2" /><ellipse cx="150" cy="100" rx="100" ry="50"
fill="purple" stroke="yellow" stroke-width="2" />cx,cy:椭圆中心坐标rx:水平半径ry:垂直半径
线 (line)
svg
<line x1="50" y1="50" x2="250" y2="150"
stroke="red" stroke-width="3" /><line x1="50" y1="50" x2="250" y2="150"
stroke="red" stroke-width="3" />x1,y1:起点坐标x2,y2:终点坐标
折线 (polyline)
svg
<polyline points="50,100 100,50 150,100 200,50 250,100"
fill="none" stroke="blue" stroke-width="3" /><polyline points="50,100 100,50 150,100 200,50 250,100"
fill="none" stroke="blue" stroke-width="3" />points:折线顶点坐标列表,格式为x1,y1 x2,y2 x3,y3...
多边形 (polygon)
svg
<polygon points="150,50 250,150 50,150"
fill="orange" stroke="black" stroke-width="2" /><polygon points="150,50 250,150 50,150"
fill="orange" stroke="black" stroke-width="2" />points:多边形顶点坐标列表,格式为x1,y1 x2,y2 x3,y3...- 自动闭合路径
路径 (path)
路径是最强大的SVG元素,可用于创建任何形状。
svg
<path d="M150 50 L250 150 L50 150 Z"
fill="pink" stroke="red" stroke-width="2" /><path d="M150 50 L250 150 L50 150 Z"
fill="pink" stroke="red" stroke-width="2" />d:路径数据,包含以下命令:M:移动到 (Move to)L:直线到 (Line to)H:水平直线到 (Horizontal line to)V:垂直直线到 (Vertical line to)C:三次贝塞尔曲线 (Cubic Bezier curve)S:平滑三次贝塞尔曲线 (Smooth cubic Bezier curve)Q:二次贝塞尔曲线 (Quadratic Bezier curve)T:平滑二次贝塞尔曲线 (Smooth quadratic Bezier curve)A:椭圆弧 (Elliptical arc)Z:闭合路径 (Close path)
SVG样式
内联样式
svg
<rect x="50" y="50" width="200" height="100"
style="fill: blue; stroke: red; stroke-width: 2; rx: 10; ry: 10;" /><rect x="50" y="50" width="200" height="100"
style="fill: blue; stroke: red; stroke-width: 2; rx: 10; ry: 10;" />CSS样式
svg
<svg>
<style>
.my-rect {
fill: blue;
stroke: red;
stroke-width: 2;
rx: 10;
ry: 10;
}
</style>
<rect x="50" y="50" width="200" height="100" class="my-rect" />
</svg><svg>
<style>
.my-rect {
fill: blue;
stroke: red;
stroke-width: 2;
rx: 10;
ry: 10;
}
</style>
<rect x="50" y="50" width="200" height="100" class="my-rect" />
</svg>外部CSS
html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<svg>
<rect x="50" y="50" width="200" height="100" class="my-rect" />
</svg>
</body>
</html><!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<svg>
<rect x="50" y="50" width="200" height="100" class="my-rect" />
</svg>
</body>
</html>SVG变换
平移 (translate)
svg
<rect x="50" y="50" width="100" height="100" fill="blue"
transform="translate(50, 50)" /><rect x="50" y="50" width="100" height="100" fill="blue"
transform="translate(50, 50)" />旋转 (rotate)
svg
<rect x="100" y="100" width="100" height="100" fill="red"
transform="rotate(45)" /><rect x="100" y="100" width="100" height="100" fill="red"
transform="rotate(45)" />缩放 (scale)
svg
<rect x="100" y="100" width="100" height="100" fill="green"
transform="scale(0.5)" /><rect x="100" y="100" width="100" height="100" fill="green"
transform="scale(0.5)" />倾斜 (skew)
svg
<rect x="100" y="100" width="100" height="100" fill="purple"
transform="skewX(30)" /><rect x="100" y="100" width="100" height="100" fill="purple"
transform="skewX(30)" />复合变换
svg
<rect x="100" y="100" width="100" height="100" fill="orange"
transform="translate(50, 50) rotate(45) scale(0.5)" /><rect x="100" y="100" width="100" height="100" fill="orange"
transform="translate(50, 50) rotate(45) scale(0.5)" />SVG动画
SMIL动画
svg
<rect x="50" y="50" width="100" height="100" fill="blue">
<animate attributeName="width" from="100" to="200" dur="2s" repeatCount="indefinite" />
<animate attributeName="height" from="100" to="150" dur="2s" repeatCount="indefinite" />
<animate attributeName="fill" from="blue" to="red" dur="2s" repeatCount="indefinite" />
</rect><rect x="50" y="50" width="100" height="100" fill="blue">
<animate attributeName="width" from="100" to="200" dur="2s" repeatCount="indefinite" />
<animate attributeName="height" from="100" to="150" dur="2s" repeatCount="indefinite" />
<animate attributeName="fill" from="blue" to="red" dur="2s" repeatCount="indefinite" />
</rect>CSS动画
svg
<svg>
<style>
@keyframes pulse {
0% { transform: scale(1); fill: blue; }
50% { transform: scale(1.2); fill: red; }
100% { transform: scale(1); fill: blue; }
}
.animated-rect {
animation: pulse 2s infinite;
}
</style>
<rect x="100" y="100" width="100" height="100" class="animated-rect" />
</svg><svg>
<style>
@keyframes pulse {
0% { transform: scale(1); fill: blue; }
50% { transform: scale(1.2); fill: red; }
100% { transform: scale(1); fill: blue; }
}
.animated-rect {
animation: pulse 2s infinite;
}
</style>
<rect x="100" y="100" width="100" height="100" class="animated-rect" />
</svg>SVG滤镜
高斯模糊 (Gaussian Blur)
svg
<defs>
<filter id="blur">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" />
</filter>
</defs>
<rect x="100" y="100" width="100" height="100" fill="blue" filter="url(#blur)" /><defs>
<filter id="blur">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" />
</filter>
</defs>
<rect x="100" y="100" width="100" height="100" fill="blue" filter="url(#blur)" />阴影 (Drop Shadow)
svg
<defs>
<filter id="shadow">
<feDropShadow dx="5" dy="5" stdDeviation="3" flood-color="black" flood-opacity="0.5" />
</filter>
</defs>
<rect x="100" y="100" width="100" height="100" fill="red" filter="url(#shadow)" /><defs>
<filter id="shadow">
<feDropShadow dx="5" dy="5" stdDeviation="3" flood-color="black" flood-opacity="0.5" />
</filter>
</defs>
<rect x="100" y="100" width="100" height="100" fill="red" filter="url(#shadow)" />SVG文本
基本文本
svg
<text x="150" y="100" font-size="24" fill="blue" text-anchor="middle">Hello SVG!</text><text x="150" y="100" font-size="24" fill="blue" text-anchor="middle">Hello SVG!</text>多行文本
svg
<text x="150" y="100" font-size="24" fill="green" text-anchor="middle">
<tspan x="150" dy="0">第一行文本</tspan>
<tspan x="150" dy="30">第二行文本</tspan>
<tspan x="150" dy="30">第三行文本</tspan>
</text><text x="150" y="100" font-size="24" fill="green" text-anchor="middle">
<tspan x="150" dy="0">第一行文本</tspan>
<tspan x="150" dy="30">第二行文本</tspan>
<tspan x="150" dy="30">第三行文本</tspan>
</text>文本路径
svg
<defs>
<path id="curve" d="M50,150 Q150,50 250,150" fill="none" stroke="transparent" />
</defs>
<text font-size="24" fill="purple">
<textPath href="#curve">文本沿曲线排列</textPath>
</text><defs>
<path id="curve" d="M50,150 Q150,50 250,150" fill="none" stroke="transparent" />
</defs>
<text font-size="24" fill="purple">
<textPath href="#curve">文本沿曲线排列</textPath>
</text>SVG渐变
线性渐变
svg
<defs>
<linearGradient id="linear-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="yellow" />
<stop offset="100%" stop-color="green" />
</linearGradient>
</defs>
<rect x="100" y="100" width="200" height="100" fill="url(#linear-gradient)" /><defs>
<linearGradient id="linear-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="yellow" />
<stop offset="100%" stop-color="green" />
</linearGradient>
</defs>
<rect x="100" y="100" width="200" height="100" fill="url(#linear-gradient)" />径向渐变
svg
<defs>
<radialGradient id="radial-gradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="0%" stop-color="white" />
<stop offset="100%" stop-color="blue" />
</radialGradient>
</defs>
<circle cx="150" cy="150" r="100" fill="url(#radial-gradient)" /><defs>
<radialGradient id="radial-gradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="0%" stop-color="white" />
<stop offset="100%" stop-color="blue" />
</radialGradient>
</defs>
<circle cx="150" cy="150" r="100" fill="url(#radial-gradient)" />SVG与JavaScript
html
<!DOCTYPE html>
<html>
<body>
<svg id="my-svg" width="300" height="200">
<rect id="my-rect" x="50" y="50" width="100" height="100" fill="blue" />
</svg>
<script>
// 获取SVG元素
const svg = document.getElementById('my-svg');
const rect = document.getElementById('my-rect');
// 改变属性
rect.setAttribute('fill', 'red');
rect.setAttribute('width', '150');
// 添加事件监听
rect.addEventListener('click', function() {
this.setAttribute('fill', this.getAttribute('fill') === 'red' ? 'blue' : 'red');
});
// 创建新元素
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttribute('cx', '200');
circle.setAttribute('cy', '100');
circle.setAttribute('r', '50');
circle.setAttribute('fill', 'green');
svg.appendChild(circle);
</script>
</body>
</html><!DOCTYPE html>
<html>
<body>
<svg id="my-svg" width="300" height="200">
<rect id="my-rect" x="50" y="50" width="100" height="100" fill="blue" />
</svg>
<script>
// 获取SVG元素
const svg = document.getElementById('my-svg');
const rect = document.getElementById('my-rect');
// 改变属性
rect.setAttribute('fill', 'red');
rect.setAttribute('width', '150');
// 添加事件监听
rect.addEventListener('click', function() {
this.setAttribute('fill', this.getAttribute('fill') === 'red' ? 'blue' : 'red');
});
// 创建新元素
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttribute('cx', '200');
circle.setAttribute('cy', '100');
circle.setAttribute('r', '50');
circle.setAttribute('fill', 'green');
svg.appendChild(circle);
</script>
</body>
</html>SVG最佳实践
- 使用合适的形状:根据需求选择最合适的SVG元素,简单形状使用基本元素,复杂形状使用路径
- 优化路径:减少路径点数,使用更简单的命令
- 使用CSS样式:将样式与结构分离,便于维护和修改
- 使用 viewBox:确保SVG可缩放,适应不同尺寸
- 压缩SVG:使用工具如SVGO压缩SVG文件大小
- 使用defs和use:复用图形元素,减少代码冗余
- 考虑可访问性:添加适当的title和desc元素,确保屏幕阅读器可以理解
- 测试跨浏览器兼容性:不同浏览器对SVG的支持可能有所不同
SVG优化工具
- SVGO:一个Node.js工具,用于压缩SVG文件
- Inkscape:一个开源的矢量图形编辑器,可用于创建和优化SVG
- Adobe Illustrator:专业的矢量图形编辑器,支持导出优化的SVG
- SVGOMG:SVGO的在线版本,提供可视化的优化选项
SVG应用场景
- 图标:网站和应用程序的图标
- Logo:品牌标识,可无损缩放
- 数据可视化:图表、图形和仪表盘
- 动画:网页和应用程序中的动画效果
- 交互元素:可交互的图形和控件
- 地图:交互式地图和地理数据可视化
- 游戏图形:2D游戏中的图形元素
浏览器支持
SVG在所有现代浏览器中都得到了良好的支持,包括:
- Chrome 4+
- Firefox 3.5+
- Safari 3.1+
- Edge 12+
- Internet Explorer 9+
对于旧版浏览器,可以使用SVG的替代方案,如Canvas或服务器端渲染的图片。
Cao Note