CSS 一笔画动画原理演示

在之前,曾做了一个域名和签名的一笔画动画,不过在那里仅仅是做了一个展示,没有说明它的原理。那什么是 CSS 的一笔画动画呢?这种动画通常也叫路径描边动画或线条动画。

先看下面的演示:(单击播放或暂停)

这是一个我的域名 xiaogd.net 的一笔画动画,它是如何做出来的呢?

概述

概括地讲,它是一个矢量图元素 svg 下的 path 元素,然后结合 stroke-dasharray 和 stroke-dashoffset 以及 CSS 动画属性创建出来的。

先把它的代码列举如下,然后再一步一步分析:

注:这里先不用去管那些 svg 的 viewBox 属性以及 g 元素的 transform 属性等,那些不是关键;主要关注的是 path 元素及其 d 属性(description,描述,说明)。

从一个简单的 svg path 路径说起

先创建一个简单的 path:

结果如下:

稍微解释一下,如下图示意,svg 元素先定义了一个 400×60 宽高的矩形区域:

svg path demo

path 定义了一条线段,这里是一条简单的直线,d 属性值的前段 m50 30 表示 move to (50, 30),也即定义了一个开始位置的坐标点,L350 30 表示 line to (350, 30),也即是从前一位置(在这里即是开始位置)画条直线到这个点,因为两点的 Y 坐标值相同,最终是一条长 300px 的水平线。

注意:这里的 L350 30 中的 L 是大小写敏感的,大写表示绝对坐标,小写则表示相对坐标。这里,等价的小写形式为:l300 0,表示相对前一个位置向右偏移 300,向下偏移 0(也即是不偏移,所以是水平线)。

当然,path 中也能定义各种曲线,不过直接手写的难度会非常的大,对特别复杂没有什么规律的曲线来说甚至是不可能的。像前面演示的是用矢量图工具绘制的。这些工具有 inkscape 以及阿斗伯家的 Adobe Illustrator 等。我用的是 inkscape,因为它的开源免费的,也相对轻量级些。

理解 stroke-dasharray

了解了 path 的一些最基础的知识后,现在为它增加 stroke-dasharray 属性,这里定义了四个 path,第一个没有定义 dasharray,其它三个定义了依次增大的 dasharray 值,如下所示:

那么结果是这样的:

现在你应该知道 stroke-dasharray 是什么了,就是定义了一条虚线(dash 在英文中就有虚线的意思)。

注意,也可以用样式 style 来定义,包括 stroke 和 stroke-width 等,因为这些属性本质上就是一些样式。如下用 CSS 样式的方式定义了一个 4px 宽的红色虚线:

效果是类似的:

现在对 stroke-dasharray 的值做些调整,比如这样:

那么能得到虚实长度不等同的虚线,如下所示:

现在你明白了 stroke-dasharray="30" 实际是 stroke-dasharray="30 30" 的简写形式。如果只有奇数个值,会复制成偶数个值。

stroke-dasharray="30 10 20" 实际等价于 stroke-dasharray="30 10 20 30 10 20",然后这串偶数个值按照“实线长度-虚线长度-实线长度-虚线长度-……”绘制出最终的效果。

当然,这些跟动画关系不大,只是说到它也顺便提一下。

理解 stroke-dashoffset

现在来看 stroke-dashoffset,下面定义了很多的 path,第一个是一个负数的 offset,第二个没有定义 offset(相当于 offset 为 0),其它的 offset 为正并依次增加:

结果是这样的:

stroke-dashoffset 定义了虚线开始位置的偏移量。stroke-dashoffset="10" 表示开始位置向右偏移了 10px,整体效果上则好像整条线段向左移动了 10px;负数的情况则正好相反。

另外,当不断增大 offset 时,甚至大过 dasharray 的值时,偏移在不断循环往复。不难发现,当 offset 为 60 时(最后的那条),也即正好是 dasharray 的值 30 的整数倍时,效果上跟没有定义偏移是一样的(跟第二条线效果相同):

动态改变 dashoffset 的值

通过以上示例,你应该明白了 stroke-dashoffset 的含义。而且我们看到,当不断增大 offset 时,整体效果上则好像整条线段它在不断向左移动。

可以手动调整下述滑动条自行体会一下它的效果(滑动条最右边的数字为实际的值):

0

如果我们用代码逐渐地改变 offset的值,那么就会形成一个动画的效果,这点正好可以使用 CSS 动画来达到:

.animated {animation: sdos 2s linear infinite;}
@keyframes sdos {
  to {stroke-dashoffset: 60;}
}

这里,path 的 stroke-dashoffset 的初始值为 0,然后为其定义了一个 2 秒的动画,在这过程中,关键帧(keyframes)中的 dashoffset 会逐渐增加到 60;然后整个动画会不断重复(infinite 关键字) 结果单击播放查看:

<path class="" stroke-dashoffset="0" ... />

回到先前的例子

现在我们只差一步,就是调整参数的值直到达到一笔画的效果,还是回到最开始的示例上来,这里为其定义一个 stroke-dasharray 的初始值为 1,stroke-dashoffset 的初始值为 20,效果是这样的:

如果你此时开启动画(勾选下面的“开启动画”复选框),你将看到一个类似于“蚂蚁行军”的效果。这里为你提供了两个滑动条分别控制 dasharray 和 dashoffset,所设置的值会显示在对应滑动条的最右边。

1
20

请试着慢慢调整上述两个值,直到你获取到最终的一笔画效果,祝你好运!(如果调整不到,你也可以参考最前面的代码处的值~也是一个大概试出的值)

其实也可以根据 getTotalLength 方法算出 path 的精确长度,比如开始处 path 的 id 为 domainPath,可以这样算出所需的精确结果(约为 358):

document.getElementById('domainPath').getTotalLength();// ≈358

关于一笔画的介绍就到这里。谢谢观看!回到主页