动画
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 | 参数格式 |
|---|---|
| translate | tx [ty] |
| scale | sx [sy] |
| rotate | angle [cx cy] |
| skewX | angle |
| skewY | angle |
多重变换动画
使用 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.end | anim1 结束时开始 |
| anim1.begin | anim1 开始时开始 |
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
动画 transform 和 opacity 属性性能最好,因为它们可以由 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>
避免布局抖动
避免动画会触发重排的属性,如 x、y、width、height。使用 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 动画提供最大的灵活性。选择合适的动画方式取决于需求复杂度和性能要求。使用 transform 和 opacity 进行动画可以获得最佳性能。