pin_drop当前位置:知识文库 ❯ 图文
多媒体:SVG简介 - 完整教程与代码示例
一、教程简介
SVG(Scalable Vector Graphics,可缩放矢量图形)是 W3C 制定的基于 XML 的矢量图形标准。与 Canvas 的位图渲染不同,SVG 使用 XML 描述图形,每个图形元素都是 DOM 节点,可以通过 CSS 和 JavaScript 进行操作。本教程将带你了解 SVG 的基本概念、<svg> 标签的使用、SVG 与 Canvas 的核心区别,以及 SVG 的适用场景。
二、核心概念
什么是 SVG
SVG 是一种使用 XML 描述二维矢量图形的标记语言,具有以下特点:
-
矢量图形:基于数学公式描述,无限缩放不失真
-
DOM 元素:每个图形都是 DOM 节点,可单独操作
-
文本可读:SVG 代码是纯文本,可编辑、可搜索
-
样式可控:支持 CSS 样式和 JavaScript 交互
-
动画支持:内置 SMIL 动画,也支持 CSS 动画
SVG 坐标系
SVG 使用与 Canvas 类似的坐标系:
-
原点
(0, 0)在左上角 -
X 轴向右为正方向
-
Y 轴向下为正方向
-
单位可以是 px、em、%、pt 等
SVG 与 Canvas 的核心区别
三、语法与用法
svg 标签
代码示例
<svg width="400" height="300" xmlns="http://www.w3.org/2000/svg">
<!-- SVG 内容 -->
</svg>常用属性:
viewBox 属性
viewBox 定义 SVG 的内部坐标系,格式为 min-x min-y width height:
代码示例
<!-- viewBox 定义内部坐标系为 0 0 100 100 -->
<!-- 实际显示尺寸为 400x400 -->
<svg width="400" height="400" viewBox="0 0 100 100">
<!-- 圆心在 (50,50),半径 40,在 viewBox 坐标系中 -->
<circle cx="50" cy="50" r="40" fill="#58a6ff" />
</svg>内联 SVG 与外部引用
代码示例
<!-- 方式1:内联 SVG(推荐) -->
<svg width="200" height="200">
<circle cx="100" cy="100" r="50" fill="red" />
</svg>
<!-- 方式2:img 标签引用 -->
<img src="image.svg" alt="SVG 图像" />
<!-- 方式3:CSS 背景引用 -->
<div style="background: url('image.svg');"></div>
<!-- 方式4:object 标签引用 -->
<object data="image.svg" type="image/svg+xml"></object>四、代码示例
示例1:SVG 基本概念演示
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SVG 基本概念演示</title>
<style>
body {
margin: 0;
padding: 20px;
background: #0d1117;
color: #c9d1d9;
font-family: 'Segoe UI', sans-serif;
display: flex;
flex-direction: column;
align-items: center;
}
h1 { margin-bottom: 10px; }
.demo-grid {
display: flex;
gap: 20px;
flex-wrap: wrap;
justify-content: center;
}
.card {
background: #161b22;
border: 1px solid #30363d;
border-radius: 8px;
padding: 15px;
text-align: center;
}
.card h3 {
margin: 0 0 10px 0;
font-size: 14px;
color: #58a6ff;
}
svg {
background: #0d1117;
border-radius: 4px;
}
/* SVG CSS 样式 */
.styled-rect {
fill: #3fb950;
stroke: #238636;
stroke-width: 2;
transition: fill 0.3s;
}
.styled-rect:hover {
fill: #58a6ff;
}
.styled-text {
font-family: 'Segoe UI', sans-serif;
font-size: 14px;
fill: #c9d1d9;
}
</style>
</head>
<body>
<h1>SVG 基本概念演示</h1>
<div class="demo-grid">
<!-- 基本形状 -->
<div class="card">
<h3>基本形状</h3>
<svg width="200" height="150" viewBox="0 0 200 150">
<rect x="10" y="10" width="60" height="40" fill="#e94560" rx="5" />
<circle cx="130" cy="30" r="25" fill="#58a6ff" />
<ellipse cx="50" cy="110" rx="40" ry="25" fill="#3fb950" />
<line x1="120" y1="80" x2="190" y2="140" stroke="#f8b500" stroke-width="3" />
<polygon points="150,80 190,120 110,120" fill="#d2a8ff" />
</svg>
</div>
<!-- viewBox 缩放 -->
<div class="card">
<h3>viewBox 缩放</h3>
<svg width="200" height="150" viewBox="0 0 100 75" style="border:1px dashed #30363d;">
<rect x="5" y="5" width="40" height="25" fill="#e94560" rx="3" />
<circle cx="70" cy="20" r="15" fill="#58a6ff" />
<text x="50" y="65" text-anchor="middle" class="styled-text" font-size="8">
viewBox="0 0 100 75"
</text>
</svg>
</div>
<!-- CSS 样式 -->
<div class="card">
<h3>CSS 样式交互</h3>
<svg width="200" height="150" viewBox="0 0 200 150">
<rect class="styled-rect" x="20" y="20" width="70" height="50" rx="8" />
<rect class="styled-rect" x="110" y="20" width="70" height="50" rx="8" />
<rect class="styled-rect" x="65" y="85" width="70" height="50" rx="8" />
<text x="100" y="145" text-anchor="middle" font-size="11" fill="#8b949e">
鼠标悬停变色
</text>
</svg>
</div>
<!-- 渐变与滤镜 -->
<div class="card">
<h3>渐变与滤镜</h3>
<svg width="200" height="150" viewBox="0 0 200 150">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#e94560" />
<stop offset="100%" style="stop-color:#58a6ff" />
</linearGradient>
<filter id="shadow1">
<feDropShadow dx="2" dy="2" stdDeviation="3" flood-color="#000" flood-opacity="0.5" />
</filter>
</defs>
<rect x="20" y="15" width="160" height="50" rx="10" fill="url(#grad1)" filter="url(#shadow1)" />
<text x="100" y="45" text-anchor="middle" fill="#fff" font-size="16" font-weight="bold">
渐变 + 阴影
</text>
<circle cx="60" cy="110" r="30" fill="url(#grad1)" filter="url(#shadow1)" />
<circle cx="140" cy="110" r="30" fill="url(#grad1)" opacity="0.6" />
</svg>
</div>
</div>
<div style="margin-top:20px; max-width:800px;">
<h2 style="font-size:16px; color:#58a6ff;">SVG vs Canvas 对比</h2>
<svg width="800" height="200" viewBox="0 0 800 200">
<!-- 表头 -->
<rect x="0" y="0" width="800" height="30" fill="#21262d" />
<text x="100" y="20" text-anchor="middle" fill="#c9d1d9" font-size="12" font-weight="bold">特性</text>
<text x="300" y="20" text-anchor="middle" fill="#58a6ff" font-size="12" font-weight="bold">SVG</text>
<text x="550" y="20" text-anchor="middle" fill="#3fb950" font-size="12" font-weight="bold">Canvas</text>
<!-- 数据行 -->
<g font-size="11" fill="#8b949e">
<text x="100" y="52" text-anchor="middle">渲染模式</text>
<text x="300" y="52" text-anchor="middle">保留模式 (DOM)</text>
<text x="550" y="52" text-anchor="middle">即时模式 (像素)</text>
<text x="100" y="77" text-anchor="middle">缩放</text>
<text x="300" y="77" text-anchor="middle" fill="#3fb950">无损缩放</text>
<text x="550" y="77" text-anchor="middle" fill="#e94560">缩放模糊</text>
<text x="100" y="102" text-anchor="middle">事件处理</text>
<text x="300" y="102" text-anchor="middle" fill="#3fb950">元素级事件</text>
<text x="550" y="102" text-anchor="middle" fill="#e94560">手动碰撞检测</text>
<text x="100" y="127" text-anchor="middle">大量元素</text>
<text x="300" y="127" text-anchor="middle" fill="#e94560">性能下降</text>
<text x="550" y="127" text-anchor="middle" fill="#3fb950">性能稳定</text>
<text x="100" y="152" text-anchor="middle">文本搜索</text>
<text x="300" y="152" text-anchor="middle" fill="#3fb950">可搜索</text>
<text x="550" y="152" text-anchor="middle" fill="#e94560">不可搜索</text>
<text x="100" y="177" text-anchor="middle">适用场景</text>
<text x="300" y="177" text-anchor="middle">图标/图表/地图</text>
<text x="550" y="177" text-anchor="middle">游戏/图像处理</text>
</g>
<!-- 分隔线 -->
<line x1="200" y1="30" x2="200" y2="200" stroke="#30363d" />
<line x1="400" y1="30" x2="400" y2="200" stroke="#30363d" />
<line x1="0" y1="30" x2="800" y2="30" stroke="#30363d" />
</svg>
</div>
</body>
</html>示例2:viewBox 与响应式 SVG
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>viewBox 与响应式 SVG</title>
<style>
body {
margin: 0;
padding: 20px;
background: #1a1a2e;
color: #eee;
font-family: 'Segoe UI', sans-serif;
display: flex;
flex-direction: column;
align-items: center;
}
.container {
display: flex;
gap: 20px;
flex-wrap: wrap;
justify-content: center;
}
.box {
background: #16213e;
border: 1px solid #333;
border-radius: 8px;
padding: 15px;
text-align: center;
}
.box h3 { color: #58a6ff; font-size: 14px; margin: 0 0 10px; }
.responsive-svg {
width: 100%;
max-width: 300px;
height: auto;
}
</style>
</head>
<body>
<h1>viewBox 与响应式 SVG</h1>
<div class="container">
<div class="box" style="width:220px;">
<h3>固定尺寸 200x150</h3>
<svg width="200" height="150" xmlns="http://www.w3.org/2000/svg">
<rect width="200" height="150" fill="#0f172a" />
<circle cx="100" cy="75" r="50" fill="#e94560" />
<text x="100" y="80" text-anchor="middle" fill="#fff" font-size="14">固定</text>
</svg>
</div>
<div class="box" style="width:220px;">
<h3>viewBox 缩放</h3>
<svg width="200" height="150" viewBox="0 0 100 75" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="75" fill="#0f172a" />
<circle cx="50" cy="37.5" r="25" fill="#58a6ff" />
<text x="50" y="42" text-anchor="middle" fill="#fff" font-size="7">viewBox</text>
</svg>
</div>
<div class="box" style="width:220px;">
<h3>响应式 SVG</h3>
<svg class="responsive-svg" viewBox="0 0 100 75" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="75" fill="#0f172a" />
<circle cx="50" cy="37.5" r="25" fill="#3fb950" />
<text x="50" y="42" text-anchor="middle" fill="#fff" font-size="7">响应式</text>
</svg>
</div>
</div>
</body>
</html>五、浏览器兼容性
六、注意事项与最佳实践
1. 始终指定 xmlns
代码示例
<!-- 独立 SVG 文件需要 xmlns -->
<svg xmlns="http://www.w3.org/2000/svg">
<!-- 内容 -->
</svg>
<!-- 内联 SVG 在 HTML5 中可省略 xmlns -->
<svg>
<!-- 内容 -->
</svg>2. 使用 viewBox 实现响应式
代码示例
<!-- 推荐:使用 viewBox + width:100% -->
<svg viewBox="0 0 100 100" style="width:100%;height:auto;">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>3. SVG 性能优化
-
减少不必要的嵌套
<g>元素 -
避免过多的滤镜效果
-
使用
<use>复用元素 -
对于复杂图形,考虑使用 Canvas
4. 可访问性
代码示例
<svg role="img" aria-label="一个红色的圆形">
<title>红色圆形</title>
<desc>这是一个填充为红色的圆形图形</desc>
<circle cx="50" cy="50" r="40" fill="red" />
</svg>5. SVG 作为 CSS 背景
代码示例
.icon {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2L2 7l10 5 10-5-10-5z' fill='%2358a6ff'/%3E%3C/svg%3E");
width: 24px;
height: 24px;
}七、代码规范示例
代码示例
<!-- 推荐:SVG 文件标准结构 -->
<svg xmlns="http://www.w3.org/2000/svg"
width="200" height="200"
viewBox="0 0 200 200"
role="img"
aria-label="描述文字">
<title>图形标题</title>
<desc>图形详细描述</desc>
<defs>
<!-- 渐变、滤镜、图案等定义 -->
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#e94560" />
<stop offset="100%" stop-color="#58a6ff" />
</linearGradient>
</defs>
<!-- 图形内容 -->
<g id="main-group">
<rect x="10" y="10" width="180" height="180" rx="10" fill="url(#grad1)" />
</g>
</svg>八、常见问题与解决方案
常见问题
SVG 在 IE 中不显示?
确保使用 xmlns,避免使用 IE 不支持的特性(如 SMIL 动画),使用 polyfill 库。
SVG 缩放后文字变形?
使用 vector-effect="non-scaling-stroke" 防止描边缩放,或调整 viewBox。
如何让 SVG 自适应容器大小?
使用 viewBox 配合 preserveAspectRatio 属性,并设置 CSS 宽度为 100%。
SVG 内联与外部引用的选择?
需要 CSS/JS 交互时使用内联,仅展示时使用外部引用。内联 SVG 可以直接使用 CSS 样式和 JavaScript 操作,但会增加 HTML 文件大小。
九、总结
SVG 是 Web 矢量图形的标准,关键要点:
-
矢量图形:基于 XML 描述,无限缩放不失真
-
DOM 元素:每个图形都是 DOM 节点,可独立操作和添加事件
-
viewBox:定义内部坐标系,实现响应式缩放
-
CSS 样式:SVG 元素支持 CSS 样式和过渡动画
-
保留模式:与 Canvas 的即时模式形成对比
-
适用场景:图标、图表、地图、信息图等
下一教程将介绍 SVG 基本形状的绘制。
本文涉及AI创作
内容由AI创作,请仔细甄别