CSS 打字特效

3,551 阅读5分钟

大家好,我是 Steven。

这期会介绍如何制作打字这个特效,这个教学分为两个部份。

首先是用纯 CSS 制作的简单版打字效果:

intro-1.gif

以及一个进阶版,动画效果更加细致及流畅,这就会用上 JavaScript:

intro-2.gif

那我们就开始吧。

这个教程的视频版本在 www.bilibili.com/video/BV1NV… ,欢迎三连关注!

HTML 的部分

打开 CodePen 编辑器,在 HTML 的部份加入一个 <h1> 标签,内容文字是 CodingStartup。

01.png

CSS 的部分

去到 CSS 的部份,先设定基础的文字大小,加入 :root 选择器,将文字大小设定为 20px。然后加入 body 选择器,用 Flex 的方法将内容上下左右置中。

加入 h1 选择器,将文字大小设定为 6remmarginpadding 设定为 0

02.png

好了,我们要实现打字效果,即是文字会逐一显示出来,在纯 CSS 的情况下,首先要套用一套等宽的字体,即是每一个文字的宽度都是相同的,尤其我们写代码的,编辑器用的字体几乎都是等宽字体,这样在阅读代码时才会更有效率。

font-family 设定为 monospace,这款字体也挺常用来作为编辑器的字体的。

03.png

CSS 中的 ch 单位

好了,这里介绍一个 CSS 的单位 chch 是 character 的意思,即是一个单字,1ch 的宽度等于数目字 0 的宽度。

而由于我们用上了等宽字体,所以 1ch 就等于任何英文字、数字、符号等的宽度。好了,试试设定宽度是 1ch,然后加入 overflow: hidden,现在只是看到 C 这个字元:

04.png

改为 6ch 的话,就可以看到 Coding 6 个字了:

05.png

CSS 动画

来到这里,就差一个动画的设定。加入 @keyframes typing,并设定 fromto 两个动画的区块,from 的区块内设定宽度是 1ch,而 CodingStartup 总共有 13 个英文字,所以 to 的区块内设定宽度是 13ch

06.png

回到 h1 的设定里面,加入 animation: 2s typing forwards,现在可以看到文字出现的效果:

07.gif

不过打字是逐个字显示的,所以加入加速度函数的设定 steps(13, jump-none),代表这个动画会分为 13 格去显示,现在可以看到基础版的打字效果就已经完成了:

08.gif

好了,我觉得现在的效果过于生硬,想将它改得优美一点,每个字随着游标快速滑入。

进阶版

先将宽度、overflow 以及动画的设定移除,然后加入 position: relative,现在会在文字后面加上游标。

加入 h1::after 伪类选择器,content 设定为空白字串,这样它才会显示出来。然后 display 设定为 inline-blockpositon 设定为 absolute,宽度设定为 20px,高度设定为 6rem。背景颜色设定为黑色,然后配合一下字体,加入很小的圆角设定,border-radius 设定为 2px。再将它稍为向右移一点,right 设定为 -30px

09.png

游标是会闪烁的,所以加入动画的设定 @keyframes cursor,加入 fromto 的区块,fromopacity 设定为 0,而 toopacity 设定为 1

再套用动画,设定 animation1.1s cursor steps(2, jump-none) infinite,即是用 1.1 秒的时间执行名为 cursor 的动画。然后同样地,我想动画只用 2 个影格去显示,不要渐入渐出的效果,所以设定为 steps(2),然后 infinite 代表无限重覆这个动画:

10.gif

好了,接着处理打字效果的部份,由于我想一个一个字进入,但又想每个字母都与游标有一种滑入的效果,所以我们首先要将每个文字都套用一个标签。

去到 JavaScript 的部份,定义一个常量 h1,获取 h1 这个元素。然后 h1.innerHTML 等于 h1.textContent.replace,通过正则表达式为每个字母都套上一层 <span>,现在可以通过开发者工具,确认已经套上:

11.gif

然后就是逐字进入的效果,加入 h1 span 选择器,设定 displayinline-block,然后运用与刚才相同的原理,overflow 设定为 hidden,宽度设定为 0ch。现在每一个文字,即是 span 标签的宽度都是 0,只要将它改为 1ch,就会显示出来。

12.png

加入 @keyframes text-in,同样加入 fromto 的区块,from 的宽度设定为 0chto 的宽度设定为 1ch

试试套用动画的设定,animation 设定为 1s text-in ease-in-out forwards,现在可以看到所有文字在同一秒钟滑入:

13.gif

所以需要为每个文字加入一个动画延时的设定,这里会用到 CSS 的变量。加入 animation-delay,设定为 var(--delay),而这个 --delay 的设定值会在 JavaScript 那边赋予。

14.png

回到 JavaScript 的部份,加入 document.querySelectorAll('span'),用 forEach 将所有 span 通过回圈获取出来,在回圈外定义一个变量 delay,回圈每执行一次 delay 变量会加 1,然后运用 span.style.setProperty(),将延迟的秒数设定到 --delay 这个 CSS 变量上。

15.gif

现在可以看到文字是一个接着一个出现的了,不过动画的速度太慢,我们将 1 秒改为 0.1 秒,以及判断当 index 等于 6 的时候,即是去到 Startup 那个 S 的时候再延迟多一点点,这样就更像是真实的打字情形。

16.gif

好了,打字的效果基本上都完成了,再来最后一些优化。我想在打字过程中,游标是不闪烁的,打完后才闪烁。将闪烁的动画设定分拆出来,加入 h1.ended::after 选择器,将设定移到这里。即是当 h1ended 这个 class 时游标才会闪烁。

17.png

在 JavaScript 中监听一下动画完成的事件,加入 h1animationend 事件监听器,判断当 e.target 等于最后一个 span 的时候,为 h1 加上 ended 这个 class。

18.png

还有就是大家会发现 CodingStartup 这个字会完整出现,然后才开始打字的效果,原因是 animation-delay 的设定值一开始时是空值,所以就在没有延迟的情况下执行了一次。只需要为 --delay 加入一个比较大的预设值,例如 10s 就可以了。

19.png

我们来看看这个案例的完成效果

简单版(纯 CSS):

intro-1.gif

进阶版(JavaScript):

intro-2.gif

以上,就是这期要介绍的全部内容。


这个案例的源代码在 codepen.io/stevenlei/p…

你的支持是我的动力,请关注 CodingStartup 起码课,我们一起加油!