两个属性,一个想法
一条 SVG 描边可以画成一段段虚线,而不必是实线。stroke-dasharray 描述这个图案——每段实线的长度、以及它们之间间隙的长度;stroke-dashoffset 则说明图案从路径的哪个位置开始。
模型就这么简单。数组决定图案的形状,偏移决定它的位置。而线除了自身点序之外没有天生的方向,所以让图案沿它滑动,看起来就完全等于运动。
流动线效果
要让管道流动,把图案保持适中,并让偏移量每个循环后退整整一个周期。周期就是虚线段长度加间隙长度。虚线段 12、间隙 9,周期即 21;把偏移量动画到 -42,意味着走过了两个完整周期,循环因此无缝。
.flow {
stroke-dasharray: 12 9; /* 虚线段 + 间隙 = 21 周期 */
stroke-dashoffset: 0;
animation: travel 1.15s linear infinite;
}
@keyframes travel {
to { stroke-dashoffset: -42; } /* 2 × 21 */
}
负数为什么重要
递减的偏移量把图案往路径起点拉,眼睛读到的就是向前运动。把偏移改成正值,方向就翻转。除非系统确实会反向,否则让同一张图里所有箭头朝同一个方向走,否则读者会稀释掉这个信号。
自绘路径效果
同样两个属性,也能让路径"自己画出来"而不是被流动冲刷。设一段比整条路径更长的虚线、再加一段比路径更长的间隙,然后把偏移量从整条路径长度动画到零。线就会像从起点开始一笔笔画出自己。
.draw {
stroke-dasharray: 600; /* ≥ 路径长度 */
stroke-dashoffset: 600; /* 起点时完全隐藏 */
animation: draw 1.6s ease-out forwards;
}
@keyframes draw {
to { stroke-dashoffset: 0; }
}
值得注意的坑
- 周期对不齐。若行程距离不是周期的整数倍,循环会明显跳动。乘上周期倍数即可。
- 路径长度未知。手写的路径,可在控制台用
getTotalLength()一行求出精确值,做到完美自绘。 - 一次动太多。把偏移量跟缩放、模糊、旋转混在一起会埋没重点。一个会动的属性就够了。
- 忘了减弱动效。把每段偏移关键帧都包起来,让它能被关闭;静止时的路径必须始终可读。