SVG图形

SVG概述

SVG(Scalable Vector Graphics,可缩放矢量图形)是一种基于XML的矢量图形格式。与Canvas的位图不同,SVG图形在放大或缩小时不会失真,非常适合图标、图表、地图等应用场景。

东巴文(db-w.cn) 认为:SVG是Web图形技术的瑰宝,矢量特性让它成为响应式设计的理想选择。

SVG特点

优点

特点 说明
矢量图形 放大缩小不失真
文件小 适合简单图形
可搜索 文本可被搜索引擎索引
可样式化 支持CSS样式
可动画 支持SMIL动画
可交互 支持JavaScript操作

SVG与Canvas对比

特性 SVG Canvas
图形类型 矢量图形 位图图形
缩放 不失真 会失真
性能 适合少量图形 适合大量图形
事件处理 每个元素可添加事件 需要手动计算
适用场景 图标、图表、地图 游戏、图像处理

东巴文点评:SVG和Canvas各有优势,选择哪种技术取决于具体应用场景。

SVG引入方式

1. 内联SVG

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>内联SVG示例</title>
</head>
<body>
    <svg width="200" height="200">
        <circle cx="100" cy="100" r="50" fill="blue"/>
    </svg>
</body>
</html>

2. img标签引入

<img src="image.svg" alt="SVG图像" width="200" height="200">

3. CSS背景引入

.icon {
    width: 32px;
    height: 32px;
    background-image: url('icon.svg');
    background-size: contain;
}

4. object标签引入

<object type="image/svg+xml" data="image.svg" width="200" height="200">
    您的浏览器不支持SVG
</object>

5. iframe引入

<iframe src="image.svg" width="200" height="200"></iframe>

东巴文点评:内联SVG最灵活,可以通过CSS和JavaScript完全控制;img标签引入最简单,但功能受限。

SVG基本形状

矩形 rect

<svg width="300" height="200">
    <!-- 基本矩形 -->
    <rect x="10" y="10" width="100" height="80" fill="blue"/>
    
    <!-- 圆角矩形 -->
    <rect x="120" y="10" width="100" height="80" rx="10" ry="10" fill="green"/>
    
    <!-- 带边框矩形 -->
    <rect x="10" y="100" width="100" height="80" fill="yellow" stroke="red" stroke-width="3"/>
</svg>

属性说明

属性 说明
x 左上角X坐标
y 左上角Y坐标
width 宽度
height 高度
rx 水平圆角半径
ry 垂直圆角半径

圆形 circle

<svg width="300" height="200">
    <circle cx="100" cy="100" r="50" fill="purple"/>
    <circle cx="200" cy="100" r="40" fill="orange" stroke="black" stroke-width="2"/>
</svg>

属性说明

属性 说明
cx 圆心X坐标
cy 圆心Y坐标
r 半径

椭圆 ellipse

<svg width="300" height="200">
    <ellipse cx="150" cy="100" rx="100" ry="50" fill="cyan"/>
</svg>

属性说明

属性 说明
cx 圆心X坐标
cy 圆心Y坐标
rx 水平半径
ry 垂直半径

线条 line

<svg width="300" height="200">
    <line x1="10" y1="10" x2="200" y2="150" stroke="red" stroke-width="3"/>
</svg>

属性说明

属性 说明
x1 起点X坐标
y1 起点Y坐标
x2 终点X坐标
y2 终点Y坐标

折线 polyline

<svg width="300" height="200">
    <polyline points="10,10 50,100 100,50 150,120 200,80" 
              fill="none" stroke="blue" stroke-width="2"/>
</svg>

多边形 polygon

<svg width="300" height="200">
    <!-- 三角形 -->
    <polygon points="100,10 150,100 50,100" fill="red"/>
    
    <!-- 五角星 -->
    <polygon points="200,10 220,80 290,80 235,120 255,190 200,150 145,190 165,120 110,80 180,80" 
             fill="yellow" stroke="orange" stroke-width="2"/>
</svg>

东巴文点评polylinepolygon的区别在于,polygon会自动闭合路径。

路径 path

path是SVG中最强大的绘图元素,可以绘制任意形状。

<svg width="300" height="200">
    <!-- 三角形 -->
    <path d="M 100 10 L 150 100 L 50 100 Z" fill="green"/>
    
    <!-- 曲线 -->
    <path d="M 200 10 Q 250 100 200 150" fill="none" stroke="blue" stroke-width="2"/>
</svg>

路径命令

命令 说明 参数
M 移动到 x y
L 连线到 x y
H 水平连线 x
V 垂直连线 y
C 三次贝塞尔曲线 x1 y1 x2 y2 x y
S 平滑三次贝塞尔曲线 x2 y2 x y
Q 二次贝塞尔曲线 x1 y1 x y
T 平滑二次贝塞尔曲线 x y
A 椭圆弧 rx ry x-axis-rotation large-arc-flag sweep-flag x y
Z 闭合路径 -

东巴文点评path命令大小写有区别,大写表示绝对坐标,小写表示相对坐标。

SVG文本

基本文本

<svg width="300" height="200">
    <text x="50" y="50" font-size="24" fill="blue">东巴文SVG</text>
</svg>

文本属性

<svg width="400" height="200">
    <!-- 字体样式 -->
    <text x="10" y="30" font-family="Arial" font-size="20" font-weight="bold" fill="black">
        粗体文本
    </text>
    
    <!-- 斜体文本 -->
    <text x="10" y="60" font-style="italic" font-size="20" fill="gray">
        斜体文本
    </text>
    
    <!-- 文本装饰 -->
    <text x="10" y="90" text-decoration="underline" font-size="20" fill="blue">
        下划线文本
    </text>
    
    <!-- 文本对齐 -->
    <text x="200" y="120" text-anchor="middle" font-size="20" fill="green">
        居中文本
    </text>
</svg>

tspan元素

<svg width="400" height="200">
    <text x="50" y="50" font-size="20">
        <tspan fill="red">红色</tspan>
        <tspan fill="blue">蓝色</tspan>
        <tspan fill="green">绿色</tspan>
    </text>
    
    <text x="50" y="100" font-size="20">
        <tspan x="50" dy="0">第一行</tspan>
        <tspan x="50" dy="25">第二行</tspan>
        <tspan x="50" dy="25">第三行</tspan>
    </text>
</svg>

文本路径

<svg width="400" height="200">
    <!-- 定义路径 -->
    <defs>
        <path id="myPath" d="M 50 100 Q 200 50 350 100" fill="none"/>
    </defs>
    
    <!-- 文本沿路径排列 -->
    <text font-size="20">
        <textPath href="#myPath">东巴文SVG文本路径示例</textPath>
    </text>
</svg>

SVG样式

内联样式

<svg width="300" height="200">
    <rect x="10" y="10" width="100" height="80" 
          style="fill: blue; stroke: red; stroke-width: 3;"/>
</svg>

属性样式

<svg width="300" height="200">
    <rect x="10" y="10" width="100" height="80" 
          fill="blue" stroke="red" stroke-width="3"/>
</svg>

CSS样式

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>SVG CSS样式</title>
    <style>
        .my-rect {
            fill: blue;
            stroke: red;
            stroke-width: 3;
        }
        
        .my-rect:hover {
            fill: green;
        }
    </style>
</head>
<body>
    <svg width="300" height="200">
        <rect class="my-rect" x="10" y="10" width="100" height="80"/>
    </svg>
</body>
</html>

样式属性

属性 说明 示例
fill 填充颜色 fill="red"
stroke 描边颜色 stroke="blue"
stroke-width 描边宽度 stroke-width="2"
stroke-linecap 线端样式 stroke-linecap="round"
stroke-linejoin 线连接样式 stroke-linejoin="round"
opacity 透明度 opacity="0.5"
fill-opacity 填充透明度 fill-opacity="0.5"
stroke-opacity 描边透明度 stroke-opacity="0.5"

东巴文点评:SVG样式优先级:内联样式 > CSS样式 > 属性样式。

SVG渐变

线性渐变

<svg width="300" height="200">
    <defs>
        <linearGradient id="linearGradient1" 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="blue"/>
        </linearGradient>
    </defs>
    
    <rect x="10" y="10" width="200" height="100" fill="url(#linearGradient1)"/>
</svg>

径向渐变

<svg width="300" height="200">
    <defs>
        <radialGradient id="radialGradient1" cx="50%" cy="50%" r="50%">
            <stop offset="0%" stop-color="white"/>
            <stop offset="50%" stop-color="yellow"/>
            <stop offset="100%" stop-color="red"/>
        </radialGradient>
    </defs>
    
    <circle cx="150" cy="100" r="80" fill="url(#radialGradient1)"/>
</svg>

东巴文点评:渐变必须定义在<defs>元素中,并通过id引用。

SVG图案

图案定义

<svg width="300" height="200">
    <defs>
        <pattern id="pattern1" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
            <circle cx="10" cy="10" r="5" fill="blue"/>
        </pattern>
    </defs>
    
    <rect x="10" y="10" width="200" height="150" fill="url(#pattern1)"/>
</svg>

图案属性

属性 说明
x 图案起始X坐标
y 图案起始Y坐标
width 图案宽度
height 图案高度
patternUnits 图案单位(userSpaceOnUse/objectBoundingBox)

SVG滤镜

模糊滤镜

<svg width="300" height="200">
    <defs>
        <filter id="blur1">
            <feGaussianBlur in="SourceGraphic" stdDeviation="5"/>
        </filter>
    </defs>
    
    <rect x="10" y="10" width="100" height="80" fill="blue" filter="url(#blur1)"/>
</svg>

阴影滤镜

<svg width="300" height="200">
    <defs>
        <filter id="shadow1" x="-20%" y="-20%" width="140%" height="140%">
            <feDropShadow dx="5" dy="5" stdDeviation="3" flood-color="black" flood-opacity="0.5"/>
        </filter>
    </defs>
    
    <rect x="50" y="50" width="100" height="80" fill="blue" filter="url(#shadow1)"/>
</svg>

东巴文点评:SVG滤镜功能强大,可以实现各种图像处理效果。

SVG变换

变换属性

<svg width="300" height="200">
    <!-- 平移 -->
    <rect x="10" y="10" width="50" height="50" fill="red" transform="translate(50, 50)"/>
    
    <!-- 旋转 -->
    <rect x="100" y="10" width="50" height="50" fill="blue" transform="rotate(45, 125, 35)"/>
    
    <!-- 缩放 -->
    <rect x="200" y="10" width="50" height="50" fill="green" transform="scale(1.5)"/>
    
    <!-- 组合变换 -->
    <rect x="10" y="100" width="50" height="50" fill="purple" 
          transform="translate(100, 0) rotate(30) scale(1.2)"/>
</svg>

变换方法

方法 说明 示例
translate(tx, ty) 平移 transform="translate(50, 50)"
rotate(angle, cx, cy) 旋转 transform="rotate(45, 100, 100)"
scale(sx, sy) 缩放 transform="scale(1.5)"
skewX(angle) X轴倾斜 transform="skewX(30)"
skewY(angle) Y轴倾斜 transform="skewY(30)"
matrix(a,b,c,d,e,f) 矩阵变换 transform="matrix(1,0,0,1,50,50)"

SVG动画

SMIL动画

<svg width="300" height="200">
    <!-- 矩形移动动画 -->
    <rect x="10" y="10" width="50" height="50" fill="blue">
        <animate attributeName="x" from="10" to="200" dur="3s" repeatCount="indefinite"/>
    </rect>
    
    <!-- 圆形缩放动画 -->
    <circle cx="150" cy="100" r="20" fill="red">
        <animate attributeName="r" from="20" to="50" dur="2s" repeatCount="indefinite"/>
    </circle>
    
    <!-- 颜色变化动画 -->
    <rect x="10" y="100" width="50" height="50">
        <animate attributeName="fill" from="red" to="blue" dur="3s" repeatCount="indefinite"/>
    </rect>
</svg>

animate元素属性

属性 说明
attributeName 动画属性名
from 起始值
to 结束值
dur 持续时间
repeatCount 重复次数(indefinite表示无限)
fill 动画结束后的状态(freeze/remove)

transform动画

<svg width="300" height="200">
    <rect x="100" y="75" width="50" height="50" fill="green">
        <animateTransform attributeName="transform" type="rotate" 
                          from="0 125 100" to="360 125 100" 
                          dur="5s" repeatCount="indefinite"/>
    </rect>
</svg>

东巴文点评:SMIL动画简单易用,但兼容性不如CSS动画和JavaScript动画。

SVG与JavaScript

获取SVG元素

<svg id="mySvg" width="300" height="200">
    <rect id="myRect" x="10" y="10" width="100" height="80" fill="blue"/>
</svg>

<script>
    const svg = document.getElementById('mySvg');
    const rect = document.getElementById('myRect');
    
    // 修改属性
    rect.setAttribute('fill', 'red');
    rect.setAttribute('width', '150');
</script>

创建SVG元素

const svg = document.getElementById('mySvg');

// 创建圆形
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttribute('cx', '150');
circle.setAttribute('cy', '100');
circle.setAttribute('r', '50');
circle.setAttribute('fill', 'green');

svg.appendChild(circle);

SVG事件处理

<svg width="300" height="200">
    <rect id="myRect" x="10" y="10" width="100" height="80" fill="blue"/>
</svg>

<script>
    const rect = document.getElementById('myRect');
    
    rect.addEventListener('click', function() {
        this.setAttribute('fill', 'red');
    });
    
    rect.addEventListener('mouseenter', function() {
        this.setAttribute('opacity', '0.5');
    });
    
    rect.addEventListener('mouseleave', function() {
        this.setAttribute('opacity', '1');
    });
</script>

东巴文点评:SVG元素可以使用标准的DOM API操作,但创建元素时必须使用createElementNS方法。

SVG图标

内联SVG图标

<button class="btn">
    <svg width="16" height="16" viewBox="0 0 16 16">
        <path d="M8 0L10 6L16 8L10 10L8 16L6 10L0 8L6 6L8 0Z" fill="currentColor"/>
    </svg>
    收藏
</button>

SVG Sprite

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>SVG Sprite示例</title>
</head>
<body>
    <!-- SVG定义 -->
    <svg style="display: none;">
        <symbol id="icon-star" viewBox="0 0 16 16">
            <path d="M8 0L10 6L16 8L10 10L8 16L6 10L0 8L6 6L8 0Z"/>
        </symbol>
        
        <symbol id="icon-heart" viewBox="0 0 16 16">
            <path d="M8 14s-5.5-4.5-5.5-7.5S5 2 8 5c3-3 5.5-1.5 5.5 1.5S8 14 8 14z"/>
        </symbol>
    </svg>
    
    <!-- 使用图标 -->
    <svg width="16" height="16">
        <use href="#icon-star"/>
    </svg>
    
    <svg width="16" height="16">
        <use href="#icon-heart"/>
    </svg>
</body>
</html>

东巴文点评:SVG Sprite是管理图标的最佳方式,可以复用图标定义,减少代码重复。

响应式SVG

viewBox属性

<svg width="100%" height="auto" viewBox="0 0 300 200">
    <rect x="10" y="10" width="100" height="80" fill="blue"/>
    <circle cx="200" cy="100" r="50" fill="red"/>
</svg>

viewBox说明

viewBox="min-x min-y width height"
参数 说明
min-x 视图框左上角X坐标
min-y 视图框左上角Y坐标
width 视图框宽度
height 视图框高度

preserveAspectRatio属性

<svg width="300" height="200" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
    <rect x="0" y="0" width="100" height="100" fill="blue"/>
</svg>

preserveAspectRatio值

说明
none 不保持宽高比,拉伸填充
xMinYMin meet 保持宽高比,左上对齐
xMidYMid meet 保持宽高比,居中对齐
xMaxYMax meet 保持宽高比,右下对齐

东巴文点评viewBox是响应式SVG的核心,它定义了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 {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }
        
        svg {
            border: 1px solid #ccc;
            display: block;
            margin: 20px 0;
        }
        
        .interactive-rect {
            cursor: pointer;
            transition: all 0.3s;
        }
        
        .interactive-rect:hover {
            opacity: 0.7;
        }
    </style>
</head>
<body>
    <h1>SVG图形示例</h1>
    
    <h2>基本形状</h2>
    <svg width="600" height="200" viewBox="0 0 600 200">
        <rect x="10" y="10" width="100" height="80" fill="blue" rx="10"/>
        <circle cx="200" cy="50" r="40" fill="red"/>
        <ellipse cx="350" cy="50" rx="60" ry="30" fill="green"/>
        <line x1="450" y1="10" x2="550" y2="90" stroke="purple" stroke-width="3"/>
        <polygon points="500,100 520,150 480,150" fill="orange"/>
    </svg>
    
    <h2>渐变填充</h2>
    <svg width="600" height="150" viewBox="0 0 600 150">
        <defs>
            <linearGradient id="linearGrad" 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="blue"/>
            </linearGradient>
            
            <radialGradient id="radialGrad" cx="50%" cy="50%" r="50%">
                <stop offset="0%" stop-color="white"/>
                <stop offset="100%" stop-color="blue"/>
            </radialGradient>
        </defs>
        
        <rect x="10" y="10" width="250" height="100" fill="url(#linearGrad)"/>
        <circle cx="450" cy="60" r="50" fill="url(#radialGrad)"/>
    </svg>
    
    <h2>动画效果</h2>
    <svg width="600" height="150" viewBox="0 0 600 150">
        <rect x="10" y="50" width="50" height="50" fill="blue">
            <animate attributeName="x" from="10" to="500" dur="3s" repeatCount="indefinite"/>
        </rect>
        
        <circle cx="300" cy="75" r="20" fill="red">
            <animate attributeName="r" from="20" to="50" dur="2s" repeatCount="indefinite"/>
        </circle>
    </svg>
    
    <h2>交互式SVG</h2>
    <svg width="600" height="150" viewBox="0 0 600 150" id="interactiveSvg">
        <rect class="interactive-rect" id="rect1" x="50" y="30" width="100" height="80" fill="blue"/>
        <rect class="interactive-rect" id="rect2" x="200" y="30" width="100" height="80" fill="green"/>
        <rect class="interactive-rect" id="rect3" x="350" y="30" width="100" height="80" fill="red"/>
    </svg>
    
    <script>
        // 交互式SVG示例
        const rects = document.querySelectorAll('.interactive-rect');
        
        rects.forEach(rect => {
            rect.addEventListener('click', function() {
                const colors = ['blue', 'green', 'red', 'yellow', 'purple', 'orange'];
                const randomColor = colors[Math.floor(Math.random() * colors.length)];
                this.setAttribute('fill', randomColor);
            });
        });
    </script>
</body>
</html>

SVG最佳实践

1. 优化SVG文件

<!-- 推荐:简洁的SVG -->
<svg width="100" height="100" viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="blue"/>
</svg>

<!-- 不推荐:包含不必要的属性 -->
<svg width="100" height="100" viewBox="0 0 100 100" 
     xmlns="http://www.w3.org/2000/svg" 
     xmlns:xlink="http://www.w3.org/1999/xlink"
     version="1.1">
    <circle cx="50" cy="50" r="40" fill="blue"/>
</svg>

2. 使用CSS控制样式

<style>
    .icon {
        width: 24px;
        height: 24px;
        fill: currentColor;
    }
    
    .icon:hover {
        fill: blue;
    }
</style>

<svg class="icon" viewBox="0 0 24 24">
    <path d="M12 2L15 8L22 9L17 14L18 21L12 18L6 21L7 14L2 9L9 8L12 2Z"/>
</svg>

3. 响应式设计

<style>
    .responsive-svg {
        width: 100%;
        height: auto;
    }
</style>

<svg class="responsive-svg" viewBox="0 0 300 200">
    <!-- SVG内容 -->
</svg>

学习检验

知识点测试

问题1:SVG中用于定义可重用元素的元素是?

A. <use> B. <defs> C. <symbol> D. <g>

<details> <summary>点击查看答案</summary>

答案:B

东巴文解释<defs>元素用于定义可重用的元素,如渐变、图案、滤镜等,这些元素不会直接显示,但可以被其他元素引用。

</details>

问题2:以下哪个属性用于控制SVG的缩放行为?

A. width B. height C. viewBox D. preserveAspectRatio

<details> <summary>点击查看答案</summary>

答案:C

东巴文解释viewBox属性定义了SVG的坐标系统和缩放行为,是实现响应式SVG的关键属性。

</details>

实践任务

任务:创建一个SVG图标,实现鼠标悬停时颜色变化的效果。

<details> <summary>点击查看参考答案</summary>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>SVG图标示例</title>
    <style>
        .icon {
            width: 48px;
            height: 48px;
            fill: gray;
            cursor: pointer;
            transition: fill 0.3s;
        }
        
        .icon:hover {
            fill: #f39c12;
        }
    </style>
</head>
<body>
    <svg class="icon" viewBox="0 0 24 24">
        <path d="M12 2L15 8L22 9L17 14L18 21L12 18L6 21L7 14L2 9L9 8L12 2Z"/>
    </svg>
</body>
</html>
</details>

东巴文(db-w.cn) - 让编程学习更有趣、更高效!