跳到主要内容

动画

SVG 支持多种动画方式:SMIL 动画、CSS 动画和 JavaScript 动画。SMIL(Synchronized Multimedia Integration Language)是 SVG 原生的动画规范,CSS 动画通过 CSS 属性实现,JavaScript 动画则提供最大的灵活性。

SMIL 动画

SMIL 动画使用专门的动画元素,直接嵌入 SVG 中,无需额外的脚本或样式。

animate - 属性动画

<animate> 元素用于动画化 SVG 属性。

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="30" width="50" height="50" fill="#3498db">
<animate attributeName="x" from="10" to="140" dur="2s" repeatCount="indefinite"/>
</rect>
</svg>

属性说明

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

animateTransform - 变换动画

<animateTransform> 用于动画化变换属性。

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<rect x="75" y="75" width="50" height="50" fill="#e74c3c">
<animateTransform attributeName="transform" type="rotate"
from="0 100 100" to="360 100 100" dur="3s" repeatCount="indefinite"/>
</rect>
</svg>

变换类型

type参数格式
translatetx [ty]
scalesx [sy]
rotateangle [cx cy]
skewXangle
skewYangle

多重变换动画

使用 additive="sum" 可以叠加多个变换动画:

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<rect x="75" y="75" width="50" height="50" fill="#9b59b6">
<animateTransform attributeName="transform" type="rotate"
from="0 100 100" to="360 100 100" dur="4s" repeatCount="indefinite"/>
<animateTransform attributeName="transform" type="scale"
from="1" to="1.5" dur="2s" repeatCount="indefinite" additive="sum"/>
</rect>
</svg>

animateMotion - 路径动画

<animateMotion> 让元素沿着路径移动。

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<path d="M 20 100 Q 150 -20, 280 100" fill="none" stroke="#bdc3c7" stroke-dasharray="5"/>
<circle r="10" fill="#3498db">
<animateMotion dur="3s" repeatCount="indefinite">
<mpath href="#motion-path"/>
</animateMotion>
</circle>
<path id="motion-path" d="M 20 100 Q 150 -20, 280 100" fill="none"/>
</svg>

也可以直接在 animateMotion 中定义路径:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<circle r="10" fill="#e74c3c">
<animateMotion path="M 20 100 Q 150 -20, 280 100" dur="3s" repeatCount="indefinite"/>
</circle>
</svg>

rotate 属性

rotate 属性控制元素沿路径移动时的旋转:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<path d="M 20 100 Q 150 -20, 280 100" fill="none" stroke="#bdc3c7" stroke-dasharray="5"/>
<polygon points="0,-10 10,10 -10,10" fill="#2ecc71">
<animateMotion path="M 20 100 Q 150 -20, 280 100" dur="3s" repeatCount="indefinite" rotate="auto"/>
</polygon>
</svg>
  • auto:元素自动旋转以保持与路径切线方向一致
  • auto-reverse:与 auto 相同,但旋转 180 度

set - 设置动画

<set> 用于在特定时间设置属性值,适合离散变化:

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="25" width="100" height="50" fill="#3498db">
<set attributeName="fill" to="#e74c3c" begin="1s" dur="1s"/>
<set attributeName="fill" to="#2ecc71" begin="2s" dur="1s"/>
</rect>
</svg>

animateColor - 颜色动画

<animateColor> 专门用于颜色动画,但现代浏览器已支持直接使用 <animate> 动画化颜色:

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="50" r="40">
<animate attributeName="fill" values="#e74c3c;#3498db;#2ecc71;#e74c3c"
dur="4s" repeatCount="indefinite"/>
</circle>
</svg>

动画时间控制

values 属性:定义多个关键帧值

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<circle cx="30" cy="50" r="20" fill="#9b59b6">
<animate attributeName="cx" values="30;170;30" dur="3s" repeatCount="indefinite"/>
</circle>
</svg>

keyTimes 属性:定义每个关键帧的时间点(0-1)

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<circle cx="30" cy="50" r="20" fill="#f39c12">
<animate attributeName="cx" values="30;170;30" keyTimes="0;0.8;1" dur="3s" repeatCount="indefinite"/>
</circle>
</svg>

calcMode 属性:插值模式

说明
linear线性插值(默认)
discrete离散,不插值
paced匀速
spline贝塞尔曲线

keySplines 属性:定义每个区间的贝塞尔曲线

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<circle cx="30" cy="50" r="20" fill="#1abc9c">
<animate attributeName="cx" values="30;170" dur="2s" repeatCount="indefinite"
calcMode="spline" keySplines="0.5 0 0.5 1"/>
</circle>
</svg>

动画触发

begin 属性:定义动画开始时间

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<rect id="rect1" x="20" y="30" width="50" height="50" fill="#e74c3c">
<animate attributeName="width" from="50" to="100" dur="1s" begin="click"/>
</rect>
<rect id="rect2" x="130" y="30" width="50" height="50" fill="#3498db">
<animate attributeName="width" from="50" to="100" dur="1s" begin="rect1.click"/>
</rect>
</svg>

触发方式

说明
0s立即开始
2s延迟 2 秒开始
click点击元素开始
rect1.click点击 rect1 开始
anim1.endanim1 结束时开始
anim1.beginanim1 开始时开始

CSS 动画

SVG 元素可以使用 CSS 动画和过渡。

CSS 过渡

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<style>
.transition-rect {
fill: #3498db;
transition: fill 0.3s, transform 0.3s;
}
.transition-rect:hover {
fill: #e74c3c;
transform: scale(1.1);
}
</style>
<rect x="50" y="20" width="100" height="60" rx="10" class="transition-rect"/>
</svg>

CSS 关键帧动画

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<style>
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.2); }
}
.rotate-anim {
animation: rotate 3s linear infinite;
transform-origin: center;
}
.pulse-anim {
animation: pulse 1s ease-in-out infinite;
}
</style>
<circle cx="100" cy="100" r="50" fill="#9b59b6" class="pulse-anim"/>
</svg>

CSS 动画化 SVG 属性

部分 SVG 属性可以直接用 CSS 动画化:

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<style>
@keyframes dash {
to { stroke-dashoffset: 0; }
}
.path-anim {
stroke-dasharray: 200;
stroke-dashoffset: 200;
animation: dash 2s linear forwards;
}
</style>
<path d="M 20 50 L 180 50" stroke="#e74c3c" stroke-width="4" fill="none" class="path-anim"/>
</svg>

JavaScript 动画

JavaScript 提供最大的灵活性,可以创建复杂的交互式动画。

基本动画

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<circle id="js-circle" cx="30" cy="50" r="20" fill="#3498db"/>
<script type="text/javascript">
const circle = document.getElementById('js-circle');
let x = 30;
let direction = 1;

function animate() {
x += direction * 2;
if (x > 170 || x < 30) direction *= -1;
circle.setAttribute('cx', x);
requestAnimationFrame(animate);
}
animate();
</script>
</svg>

使用 Web Animations API

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<circle id="api-circle" cx="100" cy="50" r="30" fill="#e74c3c"/>
<script type="text/javascript">
const circle = document.getElementById('api-circle');
circle.animate([
{ transform: 'scale(1)' },
{ transform: 'scale(1.5)' },
{ transform: 'scale(1)' }
], {
duration: 1000,
iterations: Infinity
});
</script>
</svg>

GSAP 动画库

GSAP(GreenSock Animation Platform)是流行的 JavaScript 动画库:

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<rect id="gsap-rect" x="50" y="25" width="100" height="50" fill="#2ecc71"/>
</svg>
<script>
gsap.to('#gsap-rect', {
rotation: 360,
duration: 2,
repeat: -1,
ease: 'none',
transformOrigin: 'center center'
});
</script>

实用示例

加载动画

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" fill="none" stroke="#ecf0f1" stroke-width="6"/>
<circle cx="50" cy="50" r="40" fill="none" stroke="#3498db" stroke-width="6"
stroke-dasharray="80 200" stroke-linecap="round">
<animateTransform attributeName="transform" type="rotate"
from="0 50 50" to="360 50 50" dur="1s" repeatCount="indefinite"/>
</circle>
</svg>

弹跳球

<svg width="200" height="150" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="30" r="20" fill="#e74c3c">
<animate attributeName="cy" values="30;120;30" dur="1s" repeatCount="indefinite"
calcMode="spline" keySplines="0.4 0 1 1; 0 0 0.2 1"/>
</circle>
</svg>

心跳效果

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<path d="M 50 90 C 50 90, 10 55, 10 35 C 10 15, 30 10, 50 30 C 70 10, 90 15, 90 35 C 90 55, 50 90, 50 90"
fill="#e74c3c">
<animate attributeName="transform" type="scale" values="1;1.1;1"
dur="0.8s" repeatCount="indefinite" additive="sum"/>
</path>
</svg>

路径描边动画

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<path d="M 20 80 Q 100 10, 180 80" fill="none" stroke="#3498db" stroke-width="3"
stroke-dasharray="200" stroke-dashoffset="200">
<animate attributeName="stroke-dashoffset" from="200" to="0" dur="2s" fill="freeze"/>
</path>
</svg>

打字机效果

<svg width="200" height="50" xmlns="http://www.w3.org/2000/svg">
<text x="20" y="35" font-family="monospace" font-size="24" fill="#2c3e50">
Hello!
<animate attributeName="opacity" values="0;1" dur="0.1s" begin="0s" fill="freeze"/>
</text>
<rect x="90" y="10" width="2" height="30" fill="#2c3e50">
<animate attributeName="opacity" values="1;0" dur="0.5s" repeatCount="indefinite"/>
</rect>
</svg>

动画性能优化

使用 transform 和 opacity

动画 transformopacity 属性性能最好,因为它们可以由 GPU 加速:

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<style>
.optimized {
will-change: transform;
animation: move 2s infinite;
}
@keyframes move {
0%, 100% { transform: translateX(0); }
50% { transform: translateX(100px); }
}
</style>
<rect x="20" y="30" width="50" height="50" fill="#3498db" class="optimized"/>
</svg>

避免布局抖动

避免动画会触发重排的属性,如 xywidthheight。使用 transform 替代:

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<rect x="20" y="30" width="50" height="50" fill="#e74c3c">
<animateTransform attributeName="transform" type="translate"
from="0 0" to="100 0" dur="2s" repeatCount="indefinite"/>
</rect>
</svg>

小结

SVG 动画有三种实现方式:SMIL 动画是 SVG 原生方案,语法简洁;CSS 动画适合简单的过渡和循环效果;JavaScript 动画提供最大的灵活性。选择合适的动画方式取决于需求复杂度和性能要求。使用 transformopacity 进行动画可以获得最佳性能。