解析纯 CSS 实现的打字机效果

  |   0 评论   |   0 浏览   |   Erioifpud

https://dev.to/stokry/typing-effect-without-javascript-54ol

该效果的作者为 Stokry 与 Edwin

效果

See the Pen CSS Typing by Erioifpud (@erioifpud) on CodePen.

代码实现

<div class="container">
  <div class="type">
    This is one cool effect
  </div>
</div>
:root {
	/** This is the number of characters in the text */
	--characters: 24;
}
.container {
	height: 100vh;
	display: flex;
	align-items: center;
	justify-content: center;
	font-family: monospace;
	font-size: 2em;
}
.type {
	max-width: 0;
	animation: typing 6s steps(var(--characters)) infinite;
	white-space: nowrap;
	overflow: hidden;
}
.container:after {
	content: " |";
	animation: blink 1s infinite;
	animation-timing-function: step-end;
}
@keyframes typing {
	75%,
	100% {
		max-width: calc(var(--characters) * 1ch);
	}
}
@keyframes blink {
	0% {
		opacity: 1;
	}
	25% {
		opacity: 0;
	}
	75% {
		opacity: 1;
	}
	100% {
		opacity: 1;
	}
}

解析

首先,我们从简单的、用处不大的部分看起,将他们逐个排除。那么第一个看的是 HTML 的结构,一层容器 container包裹着输入的内容 type,很简单。

接着是 container的样式,他看起来只是一个普通的 flex容器,将内容水平、垂直居中显示,但有个关键的地方:

font-family: monospace;

这个样式将字体改成了等宽的,也就是字符宽度相同的电脑字体,这个的用处后面会解释。

DTFt0K.png

图片来源:维基百科

那么可以先将 container部分排除了,和动画有关的样式都在 type上,type也能分成两部分,分别是光标打字机

光标

光标使用伪元素 after实现,after的内容 content就是个光标的形状 " |",闪烁通过动画改变透明度 opacity实现。

animation-timing-function: step-end是必要的,因为 animation默认会给状态之间加入过渡的效果,而 animation-timing-function可以用来取消过渡效果,假如去掉这个样式,光标的闪烁就会变成渐变,从透明度 0 渐变到透明度 1,如下图:

DTFoXq.gif

animation-timing-function的实际用途和用法下面会做详细介绍。

打字机

原理是使用动画改变元素宽度type的初始最大宽度 max-width是 0,并且 overflow: hidden,也就是说超出元素的文本都会被隐藏,接着 type在动画中会逐渐变成 “This is one cool effect” 这段话的宽度,文本也就随着宽度变化显示出来了,示意图如下:

DTk4UO.png

但实现起来还是有点技巧的,首先他用了一个 CSS 变量 --characters来记录文本的长度,这个变量以后要使用两次,接着看动画的最后一个状态:

max-width: calc(var(--characters) * 1ch);

这里用了一个很罕见的单位 chch表示了字符 0 的宽度,这里用来表示任意字母的宽度

DTAiMn.png

前文提到了 container使用的是等宽字体,那么对于英文字母来说,他们的宽度都是一致的,所以文本的总宽度就能通过 --characters * 1ch计算得到了(注意,这个效果不支持中文,中文字符的宽度无法用 ch来表示)。

但只给动画中的 max-width设置文本的真实宽度后的效果如下:

DTAGdK.md.gif

可以看到文本平滑地“滚”出来了,并不是一个一个字“打”出来的,那么第二个关键点来了:

animation: typing 6s steps(var(--characters)) infinite;

animation缩写中的第三个参数表示 animation-timing-function,前面也简单提到了他的用处,实际上这个样式是用来设置动画执行节奏的,现在的动画效果是连续的,从 0ch → 24ch,但我们需要的是 24 个状态,1ch、2ch、3ch......

这就需要 steps函数来实现了,steps(n, <jumpterm>)函数的作用是 “把动画分隔成 n 个段落”,比如说 steps(5),他会把动画分隔 5 个段落。第二个参数 jumpterm表示每个分隔段上的状态取舍,默认是 end

举个完整的例子,steps(5, end)先把动画分成 5 个分隔段落:

DTAURH.md.png

0% → 20% 一段、20% → 40% 一段,以此类推有 5 段,每段都有起始(比如 0%)和结束状态(比如 20%)。

jumpterm是用来描述段落上状态取舍的,step-start会跳过起始状态,举个例子,在一个周期处于 0 到 20% 阶段时,会显示 20% 阶段的状态,直接把 0% 时的状态跳过了。step-end则相反,在一个周期处于 0 到 20% 阶段时,会显示 0% 阶段的状态,跳过 20% 时的状态,示意图如下:

DTAwQA.md.png

DTA2WQ.md.png

在一个动画周期内,step-startstep-end分别只会显示以上几个时间点的状态,不会产生连贯地过渡动画。

现在回到主题,代码中的 animation样式就很好理解了,要实现打出 24 个字的效果,就应该把这一段动画分成 24 段,然后跳过中间的过渡部分,直接显示每一个段落的结束状态

animation: typing 6s steps(var(--characters)) infinite;
/* 默认使用了step-end参数 */

总结

要实现打字机效果,关键点如下:

  • 等宽字体
  • 隐藏容器外的内容
  • 容器初始最大宽度为 0,随着动画推进至文本实际宽度(ch)
  • 使用 animation-timing-functionsteps设置动画节奏与跳帧

123


标题:解析纯 CSS 实现的打字机效果
作者:Erioifpud
地址:https://blog.doiduoyi.com/articles/1606965583810.html

评论

发表评论