SVG 内联矢量图
SVG(Scalable Vector Graphics)是一种基于 XML 的矢量图形格式。内联 SVG 是将 SVG 代码直接嵌入到 HTML 文档中,这种方式可以让你用 CSS 样式化和用 JavaScript 操作 SVG 元素。本节将介绍内联 SVG 的基本用法。
前置知识
阅读本节前,建议先了解:canvas 绘图操作
基础概念
SVG 是一种矢量图形格式,它用 XML 标记语言描述图形,而不是像素数据。与位图(如 JPEG、PNG)不同,SVG 图形可以无损缩放到任意大小,始终保持清晰。
内联 SVG(Inline SVG)是将 <svg> 标签直接放在 HTML 文档中。这种方式的优势在于:SVG 元素成为 DOM 的一部分,可以用 CSS 样式化,可以用 JavaScript 交互。
语法
基本内联 SVG
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>内联 SVG</title>
</head>
<body>
<h1>内联 SVG 基础</h1>
<!-- 基本圆形 -->
<svg width="100" height="100" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="#4285f4"/>
</svg>
<!-- 基本矩形 -->
<svg width="150" height="100" viewBox="0 0 150 100">
<rect x="10" y="10" width="130" height="80" fill="#34a853" rx="8"/>
</svg>
<!-- 基本线条 -->
<svg width="200" height="100" viewBox="0 0 200 100">
<line x1="10" y1="50" x2="190" y2="50" stroke="#ea4335" stroke-width="3"/>
</svg>
<!-- 基本多边形 -->
<svg width="120" height="120" viewBox="0 0 120 120">
<polygon points="60,10 110,90 10,90" fill="#fbbc05"/>
</svg>
</body>
</html>详细说明
SVG viewBox 属性
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>viewBox</title>
</head>
<body>
<h1>viewBox 属性</h1>
<!--
viewBox="minX minY width height"
定义了 SVG 的坐标系统和可视区域
-->
<!-- SVG 逻辑尺寸 100x100,但渲染为 200x200 -->
<svg width="200" height="200" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="#4285f4"/>
</svg>
<!-- viewBox 还可以裁剪内容 -->
<svg width="100" height="100" viewBox="25 25 50 50">
<circle cx="50" cy="50" r="40" fill="#ea4335"/>
<!-- 只显示圆的中心区域 -->
</svg>
</body>
</html>用 CSS 样式化 SVG
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>CSS 样式化 SVG</title>
<style>
/* SVG 的 class、id 都可以用 CSS 选择器 */
.icon-blue {
fill: #4285f4;
transition: fill 0.3s;
}
.icon-blue:hover {
fill: #1a73e8;
}
.icon-red {
fill: #ea4335;
}
.icon-outline {
fill: none;
stroke: #333;
stroke-width: 2;
}
/* SVG 的 stroke 和 fill 可以独立控制 */
.stroked-circle {
fill: rgba(66, 133, 244, 0.2);
stroke: #4285f4;
stroke-width: 2;
}
</style>
</head>
<body>
<h1>CSS 样式化 SVG</h1>
<!-- CSS 控制 fill -->
<svg width="50" height="50" viewBox="0 0 50 50">
<circle class="icon-blue" cx="25" cy="25" r="20"/>
</svg>
<svg width="50" height="50" viewBox="0 0 50 50">
<circle class="icon-red" cx="25" cy="25" r="20"/>
</svg>
<!-- CSS 控制 stroke -->
<svg width="50" height="50" viewBox="0 0 50 50">
<circle class="icon-outline" cx="25" cy="25" r="20"/>
</svg>
<!-- CSS 控制渐变 -->
<svg width="50" height="50" viewBox="0 0 50 50">
<circle class="stroked-circle" cx="25" cy="25" r="20"/>
</svg>
</body>
</html>用 JavaScript 操作 SVG DOM
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>JavaScript SVG</title>
</head>
<body>
<h1>JavaScript 操作 SVG</h1>
<svg id="mySvg" width="200" height="200" viewBox="0 0 200 200">
<circle id="myCircle" cx="100" cy="100" r="50" fill="#4285f4"/>
</svg>
<br>
<button onclick="changeColor()">改变颜色</button>
<button onclick="moveCircle()">移动圆</button>
<button onclick="animateCircle()">动画</button>
<script>
// SVG 元素是 DOM 节点,可以用 JS 操作
var circle = document.getElementById('myCircle');
function changeColor() {
circle.setAttribute('fill', '#ea4335');
}
function moveCircle() {
var cx = Math.random() * 100 + 50;
var cy = Math.random() * 100 + 50;
circle.setAttribute('cx', cx);
circle.setAttribute('cy', cy);
}
function animateCircle() {
var radius = 50;
var angle = 0;
function step() {
angle += 0.05;
var cx = 100 + Math.cos(angle) * 30;
var cy = 100 + Math.sin(angle) * 30;
circle.setAttribute('cx', cx);
circle.setAttribute('cy', cy);
circle.setAttribute('r', radius + Math.sin(angle * 3) * 10);
requestAnimationFrame(step);
}
step();
}
</script>
</body>
</html>内联 SVG 的常用形状
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>SVG 形状</title>
</head>
<body>
<h1>SVG 常用形状</h1>
<!-- circle: 圆形 -->
<svg width="60" height="60" viewBox="0 0 60 60">
<circle cx="30" cy="30" r="25" fill="#4285f4"/>
</svg>
<!-- rect: 矩形 -->
<svg width="60" height="40" viewBox="0 0 60 40">
<rect x="5" y="5" width="50" height="30" fill="#34a853" rx="5"/>
</svg>
<!-- ellipse: 椭圆 -->
<svg width="80" height="50" viewBox="0 0 80 50">
<ellipse cx="40" cy="25" rx="35" ry="20" fill="#fbbc05"/>
</svg>
<!-- line: 直线 -->
<svg width="100" height="20" viewBox="0 0 100 20">
<line x1="5" y1="10" x2="95" y2="10" stroke="#ea4335" stroke-width="3"/>
</svg>
<!-- polyline: 折线 -->
<svg width="100" height="50" viewBox="0 0 100 50">
<polyline points="10,40 30,10 50,30 70,10 90,40"
fill="none" stroke="#673ab7" stroke-width="2"/>
</svg>
<!-- polygon: 多边形 -->
<svg width="50" height="50" viewBox="0 0 50 50">
<polygon points="25,5 45,40 5,40" fill="#e91e63"/>
</svg>
<!-- path: 通用路径 -->
<svg width="80" height="60" viewBox="0 0 80 60">
<path d="M10 50 Q40 5 70 50" fill="none" stroke="#00bcd4" stroke-width="2"/>
</svg>
</body>
</html>实战示例
SVG 图标按钮
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>SVG 图标</title>
<style>
body { font-family: sans-serif; }
.icon-btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
border: 1px solid #ddd;
border-radius: 8px;
background: #fff;
cursor: pointer;
}
.icon-btn:hover {
background: #f5f5f5;
}
.icon-btn svg {
width: 20px;
height: 20px;
}
</style>
</head>
<body>
<h1>SVG 图标按钮</h1>
<!-- 搜索图标 -->
<button class="icon-btn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"/>
<line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
搜索
</button>
<!-- 首页图标 -->
<button class="icon-btn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12l9-9 9 9"/>
<path d="M9 21V12h6v9"/>
</svg>
首页
</button>
<!-- 设置图标 -->
<button class="icon-btn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="3"/>
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M16.36 16.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M16.36 7.64l1.42-1.42"/>
</svg>
设置
</button>
</body>
</html>注意事项
- 内联 SVG 会增加 HTML 文件体积,但可以被 Gzip 压缩
- SVG 元素是 DOM 的一部分,会触发浏览器重绘
- 内联 SVG 可以被搜索引擎索引(但不包含文本内容时)
- 复杂的 SVG(如地图)不适合内联
- 内联 SVG 的 CSS 和 JS 作用域与页面共享
最佳实践
- 简单图标和图形使用内联 SVG
- 使用
viewBox确保可缩放 - 使用
currentColor让 SVG 颜色跟随 CSS - 为 SVG 添加
aria-label或role="img"提升无障碍 - 使用
<title>和<desc>为 SVG 提供描述 - 复杂图形使用外部 SVG 文件通过
<img>引入
下一节
继续学习:SVG 与 canvas 对比