使用 CSS 和 JS 实现博客导航栏线条动画效果

使用 CSS 和 JS 实现博客导航栏线条动画效果
4rozeN原理
SVG 描边动画(stroke animation)是一种通过控制 SVG 元素的描边(stroke)属性,让路径逐步显示出来,产生 “手写” 或 “线条绘制” 的视觉效果。它的核心是使用:
stroke-dasharray:设置虚线的模式,等同于 “路径总长”,将整个路径打散成可动画的虚线段。stroke-dashoffset:设置虚线的偏移距离,将整条线 “推出可见范围”,通过动画逐渐归零,就像笔迹被画出来一样。@keyframes:通过 CSS 的@keyframes或 JS 动态设置这两个属性,实现逐步描边。
这样就能模拟路径从无到有的 “被画出” 的过程。所以首先我们得准备好一个能用的 SVG 图(什么是 SVG?)。
方法一
你可以使用 Adobe 的 adobe illustrator 来徒手绘制 svg 图。
怎么操作呢,就是创建好画布之后直接使用铅笔 / 钢笔 / 画笔等工具进行一个手画。
例如使用铅笔工具:

左边能看到路径锚点,右边能看到各个图层。
紧接着将其导出为 svg:

| 选项 | 推荐设置 |
|---|---|
| 样式 | 内部 CSS |
| 字体 | 转换为轮廓 |
| 图像 | 保留(无图也行) |
| 对象 ID | 保留(方便调试) |
| 小数位数 | 3 |
点击显示代码,它将调用文本编辑器让你提前查看。
svgd 代码大致是:
1 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 232.798 65.792"> |
在导出的 svg 代码中,我们最关心的是:
- 有
stroke且fill="none":动画只作用于描边部分,必须明确设置无填充 - 有使用到
<path>元素:做描边动画的图形元素,支持路径长度计算 - 有
viewBox:在不同尺寸下能比例正确
方法二
你也可以使用 adobe illustrator 的文字工具指定字体,来生成好看的字体效果,例如:

这个时候你只需要用选择工具,框选文字转换轮廓就可以得到复杂路径图层:

创建之后,按住 ctrl 键,你会发现文字上就出现了许多路径锚点:

图层中也自动有了每个字母的复合路径:

可以和方法一一样直接导出了。
1 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 203 74.13"> |
仔细观察会发现这种方式得到的 svg 代码是不符合我们的要求(见方法一)的。还需要全选到所有的路径,在属性中将填充设为 none 才行。
方法三
借助在线网站:Google Font to Svg Path 完成 Svg 的生成。

该网站提供谷歌字体供选择,也支持自己上传字体,使用起来是很方便的。
其中:
- variant:表示你选择的字体的风格 —— 正常还是斜体
- text:输入你要生成 svg 的语句或单词
- union:这个影响 svg 路径,是否要将字母看作整体
- kerning:字距
- separate characters:字符是否分离
- bezier accuracy:跟字体像素有关
- Dxf Units:尺寸单位
- Fill:填充颜色
- Stroke:线条颜色
- Stroke Width:线条宽度
- Non-scaling stroke:是否可缩放
- Fill rule:填充的规则
参数的变动会实时的更新在下方的 svg 元数据框中。
这种方法生成的 svg 也是不符合我们的要求(见 fang'fa)的,还需要到能处理 svg 的软件中将它的填充设为 none
编写 js
有了上述方法,可以得到 svg 图。这里简单说说我的方案:
- 字体:Signerica_Medium
- Google Font to Svg Path:仅 Union 勾选,Size 为 100。其余默认
- 待生成文字为:CiaoHello
当然,还需要到 Adobe Illustrator 中将填充设置成无。
有了 svg 之后,在 hexo 博客的 source\js 目录下创建 sign.js
1 | const navbarBrand = document.querySelector('.container a'); |
为什么这么写?
这里主要是利用浏览器开发者工具查看你的网站元素结构,找到导航栏的标题位置:

可以看到类名为 navbar-brand 的就是导航栏的标题区域,我们就是要将 svg 放在这里。
上图我已经做出修改,如果没有进行修改的话,你这里的 <svg> 标签应该是依照你的_config.fluid.yml 中设置的导航栏标题也就是 <strong> 标签。
修改的语句也很简单,先找到父亲 navbarBrand
1 | const navbarBrand = document.querySelector('.container a'); |
接着使用.innerHTML 设置为 svg 即可:
1 | navbarBrand.innerHTML = ` |
这样只是先将 svg 放在这里了,还需要明白怎么写动画。
可以参考文章:https://juejin.cn/post/6955857586922979364
或者视频:https://www.bilibili.com/video/BV1Qi4y1Y7Sp/
真不是摆烂,大佬讲的是真香
所以现在还需要知道每条 path 的长度,可以使用当前选择的元素.getTotalLength() 得到:
1 | const paths = document.querySelector('.container .navbar-brand .svg path') // 进一步选择到path |
如果你在之前生成 svg 的时候,生成了多条 path,这里你应该使用的是:
1 | const paths = document.querySelectorAll('.container .navbar-brand .svg path') |
给每条 path 设置上行内样式为变量 --l 方便后面 css 的编写。
编写 CSS
在 source\css 目录下创建 sign.css:
1 | .svg { |
通过样式变量使得 stroke-dasharray 和 stroke-dashoffset 属性能轻易获取到 path 的长度,也就方便了 @keyframes stroke 的编写。
另一个方法
其实有个库可以实现这种效果:Vivus.js
demo:https://maxwellito.github.io/vivus/
GIthub 地址:https://github.com/maxwellito/vivus
使用方法也很简单,只要给 svg 标签加上 id 即可:
1 | <svg id="my-svg"> |