在一些绘画或者写字的教学场景中,有时候需要演示图案或文字的完整书写步骤,例如用一个视频或者动图教大家如何画一个小星星:

在前端,其实可以通过 svg 动画来实现这种效果,接下来,就带领大家一步步完成 svg 动画的制作:
生成 svg 路径
首先,需要将图案变成 svg 格式 ,如果你的图案或文字可能是通过手绘板画的,可以用 Adobe Illustrator 来转成 svg,例如下面就是小星星 svg 完整的 HTML 结构:
html
<svg width="1000" height="500" fill="#ffffff00" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path class="star" stroke="#000000" stroke-width="3" d="M 614 142 L 614 142 C 614 142 612 146 611 149 C 606 155 602 161 598 168 C 589 180 582 192 574 205 C 560 225 546 246 533 267 C 519 286 507 306 494 326 C 486 337 477 348 469 360 C 464 366 459 372 455 378 C 452 380 450 383 448 386 C 447 387 446 388 446 390 C 445 390 444 390 445 390 C 445 389 447 389 448 389 C 449 388 451 386 453 386 C 456 383 461 382 465 380 C 472 376 479 372 487 369 C 499 362 513 356 526 350 C 541 342 557 333 573 326 C 588 318 604 311 621 304 C 633 298 646 292 659 287 C 670 281 681 276 693 272 C 700 269 707 266 715 264 C 719 262 723 260 727 259 C 728 258 730 256 732 256 C 732 255 734 255 734 255 C 734 254 732 254 732 254 C 731 253 729 254 729 254 C 725 253 722 253 720 253 C 714 252 708 251 703 251 C 694 249 685 248 677 247 C 666 245 655 244 644 244 C 632 243 619 242 608 242 C 595 240 582 239 570 238 C 557 236 544 234 532 233 C 522 231 512 231 502 231 C 494 230 485 231 478 231 C 471 230 464 230 458 230 C 452 229 448 228 443 227 C 439 226 436 225 433 225 C 430 224 428 225 426 225 C 425 224 424 224 424 224 C 423 223 422 223 423 224 C 423 224 424 225 425 226 C 427 227 431 229 434 231 C 440 234 447 238 454 243 C 464 250 473 258 483 266 C 494 274 505 283 517 293 C 529 302 541 313 554 323 C 565 331 577 338 590 346 C 598 351 608 355 617 360 C 625 364 634 369 643 374 C 650 378 658 382 666 386 C 670 387 674 389 679 391 C 680 391 682 392 685 393 C 686 393 687 393 689 393 C 690 393 691 393 692 393 C 692 393 692 393 693 393 C 693 392 693 392 693 392 C 693 391 693 391 693 391 C 692 387 692 384 691 381 C 687 371 683 362 680 353 C 675 341 671 330 667 319 C 662 307 656 297 652 286 C 647 275 642 265 639 255 C 635 245 633 235 631 225 C 628 217 626 209 625 202 C 623 197 623 191 623 187 C 622 183 621 180 621 177 C 620 174 619 171 619 169 C 618 166 619 162 619 160 C 618 157 618 155 618 153 C 617 151 617 151 617 150 C 616 148 617 147 617 146 C 617 144 617 143 617 142 C 616 141 616 141 616 141 C 615 140 616 140 616 140"></path></g>
</svg>

增加虚线边框
找到 svg 的 path,以上面的星星为例,类名是 star,为其增加 stroke-dasharray
属性就能得到虚线的小星星啦:
css
.star {
stroke-dasharray: 10;
}

stroke-dasharray
属性用来定义线条的虚线模式。它接受一系列的值,这些值定义了虚线中实线段和空白段的长度。这个属性的值是一组用逗号或空格分隔的数字,每一对数字分别代表实线长度和空白长度。如果提供了奇数个数字,则这个模式会被重复以形成一个偶数序列。
可以不断增加 stroke-dasharray
的取值,下面是取值为 30 的效果

下面是取值为 80 的效果:

可以看到stroke-dasharray
取值增加之后,虚线的间距也不断增加。
添加行军动画
为了让实线和虚线沿着路径动起来,形成类似于「蚂蚁行军」的动画效果,可以使用 stroke-dashoffset
属性用来定义虚线模式起始点的偏移。它的值是一个长度单位,指定了模式从路径的起点向前的偏移量。通过改变 stroke-dashoffset
的值,可以实现虚线沿着路径边缘的滚动效果:
css
@keyframes dash {
to {
stroke-dashoffset: 1300;
}
}
.star {
stroke-dasharray: 10;
animation: dash 30s linear infinite;
}

上面的代码中, stroke-dasharray: 10
定义了一个虚线模式,stroke-dashoffset
的值就会沿着这个路径移动模式的起始点。如果 stroke-dashoffset
的值为负数,虚线模式会向反方向偏移。
获取路径长度
在上面的动画的结尾处,stroke-dashoffset
的值 1300,这个是随便写的吗?其实不是,它的值要等于 svg 路径的长度,这样才能移动到路径的结尾,但是不同的图形有不同的长度,如何获取 svg 路径的长度呢?这要通过 JavaScript 代码来实现了:
js
const path = document.querySelector('.star')
const length = path.getTotalLength() // 1527
完成路径绘制
巧妙的地方在于:如果一开始我们就让 stroke-dasharray
的长度等于路径的长度,并且 stroke-dasharray
的偏移也是路径的长度,那么是不是就相当于在一开始的时候,整个路径都变成了虚线部分从而被「隐藏」了呢?
css
.star {
stroke-dasharray: 1527;
stroke-dashoffset: 1527;
}
然后添加动画,让其最终的 stroke-dashoffset
值为 0,那么就相当于沿着起始点开始绘制,最终停留在整个图形完成绘制的状态。
css
.star {
animation: dash 5s linear forwards;
}
@keyframes dash {
to {
stroke-dashoffset: 0;
}
}
注意 animation
中 forwards
关键字不能少,因为当动画完成后,forwards
值使得元素将保留动画序列中的最后一个关键帧的样式。也就是说,动画结束后,元素的样式将停留在动画的最终状态,而不是回到动画开始前的初始状态。

这里还有一个有意思的地方,如果我们让 stroke-dasharray
的值等于负的路径长度,就会朝着反方向移动,从而形成「倒着画」的效果:
