打字机效果是一种很酷的动画,它使文本看起来就像在页面上键入一样。
有很多方法可以使用打字机效果来增强网站的用户体验。例如,可以使用它来介绍主页上的关键概念或功能,或在整个网站中强调重要文本。
在这篇文章中,我们将探讨使用纯 CSS 和基于 JavaScript 的解决方案创建打字机效果的不同方法。出于演示目的,我们将使用以下引用。
- Learning never exhausts the mind — Leonardo da Vinci
- You teach best what you most need to learn — Richard Bach
- In youth we learn; in age we understand — Marie von Ebner-Eschenbach
标记
若要开始使用打字机效果,需要先创建结构 。此布局有两个基本元素:容器和内部元素。外部元素稍后将添加样式,将所有内容结合在一起。内部元素是显示文本的位置。
<div class="container">
<div class="typewriter"></div>
</div>
使用 steps()函数
创建打字机效果有两种方法。第一种方法是纯 CSS 解决方案,它完全依赖于 CSS 动画,而不使用任何 JavaScript 代码。
为了创建打字机效果,我们修改 width 属性的关键 typing 帧将内部元素的宽度从 0% 增加到 100%。
@keyframes typing {
from {
width: 0%;
}
to {
width: 100%;
}
}
我们从 0% 的宽度开始,这意味着没有输入任何字符。在动画结束时,元素宽度设置为原始全宽,这意味着所有字符都已完全键入。
挑战在于指出,在动画持续时间时间轴的每一步中,单个字符以从左到右的顺序出现。幸运的是,CSS 为此提供了 step() 计时功能。我们将步数传递给函数,动画执行相应的步数。
在我们的示例中,总步数与总字符数相同。如果我们将效果用于 Learning never exhausts the mind ,则步数为 48。
console.log('Learning never exhausts the mind'.length); // 48
动画声明可能如下所示:
.typewritter {
animation: typing 4s steps(48);
}
闪烁光标
为了使打字的效果更加逼真,我们希望在文本末尾添加一个闪烁的光标。有几种方法可以做到这一点,但在这种方法中,我们可以使用文本元素的右边框,而不是只为光标创建一个新元素。
首先,我们使文本的右边框透明。然后,我们在动画结束时将边框的颜色动画化为较深的阴影,以创建闪烁效果。
.typewritter {
border-right: 4px solid transparent;
}
@keyframes blink {
from {
border-right-color: transparent;
}
to {
border-right-color: rgb(15 23 42);
}
}
现在是使用 CSS 将动画与文本组合在一起的最佳时机。只需用逗号分隔动画即可。
例如,在下面的代码中,文本元素同时运行两个动画。第一个动画创建持续 4 秒的打字效果。第二个动画创建一个闪烁的光标,该光标反复淡入和淡出。
.typewritter {
animation: typing 4s steps(48), blink 1s infinite;
}
让我们回顾一下到目前为止我们所采取的步骤的进展情况。
若要使光标更可自定义,需要为其创建一个新元素。我们将它称为 cursor 元素并将其添加到容器中。
<div class="container">
<div class="typewritter">Learning never exhausts the mind</div>
<div class="cursor">|</div>
</div>
由于文本和光标元素是水平对齐的,因此我们将对容器使用 CSS flexbox。
.container {
display: flex;
align-items: center;
}
要创建闪烁效果,可以随时间更改光标的背景颜色。动画在光标元素上运行,而不是像上一节那样在文本元素上运行。请记住,光标具有透明的文本颜色,因此字符是不可见的 | 。
.cursor {
background-color: rgb(15 23 42);
color: transparent;
width: 4px;
animation: blink 1s infinite;
}
@keyframes blink {
0%, 100% {
background-color: transparent;
}
50% {
background-color: rgb(15 23 42);
}
}
查看这些动画的实际效果:
虽然该 steps() 函数可以创建流畅的动画,但它确实有一个缺点——我们需要事先知道总步骤数。这意味着,如果我们想对不同的文本进行动画处理,我们必须更新 CSS 代码,这使得代码的可重用性降低。
遗憾的是,这种方法不适用于动态文本。为了解决这个问题,让我们继续下一节。
动态更新文本
在本节中,我们将探讨使用 JavaScript 动态更新文本的方法。通过使用函数 setTimeout() 和一点代码,我们可以一次显示一个字符。
为了实现此效果,我们将定义一个名为的函数 type ,该函数每 100 毫秒调用一次。该函数检查是否已显示最后一个字符,如果没有,则显示下一个字符。
该 type 函数使用调用 charIndex 的变量来跟踪最后显示的字符的索引。然后,我们检查此索引是否小于文本的长度。如果是,我们使用该 charAt() 函数显示下一个字符并将索引增加 1。
const content = 'Learning never exhausts the mind';
const textEle = document.getElementById('text');
let charIndex = 0;
const type = () => {
if (charIndex < content.length) {
textEle.textContent += content.charAt(charIndex);
charIndex++;
setTimeout(type, 100);
}
};
要开始效果,只需调用该 type 函数。
实际上,光标仅在我们停止打字时闪烁。但是我们可以通过将闪烁的动画移动到一个单独的类来改变这一点。
.cursor__blink {
animation: blink 1s infinite;
}
此类将在光标元素中添加或删除,具体取决于文本是否已完全显示。
为了实现这一点,我们可以向 type() 函数添加一些逻辑。在下面的示例中,我们将使用 remove() 和 add() 函数动态管理 blinking 类。
const cursorEle = document.getElementById('cursor');
const type = () => {
if (charIndex < content.length) {
cursorEle.classList.remove('cursor__blink');
// ...
} else {
cursorEle.classList.add('cursor__blink');
}
};
现在,让我们深入了解这一切是如何工作的。
多个文本
让我们将示例提升到一个新的水平,并添加对多个文本的支持。为此,我们需要创建一个新函数来模拟 Backspace 键并擦除文本。
我们将这个函数 erase() 称为 。它将以与 type() 函数相反的方式工作。它将从文本元素中删除最后一个字符,并将索引减少 1,直到删除所有字符。该 cursor__blink 类将相应地在游标元素中添加或删除。
const erase = () => {
if (charIndex > 0) {
cursorEle.classList.remove('cursor__blink');
textEle.textContent = textEle.textContent.slice(0, charIndex - 1);
charIndex--;
setTimeout(erase, 100);
} else {
cursorEle.classList.add('cursor__blink');
}
};
为了跟踪我们正在处理的当前文本,我们需要调用一个新索引 arrayIndex 来访问文本列表。该 type() 函数将更新,以便我们使用当前文本。当当前文本完全显示时,我们将在 500 毫秒后开始擦除它。
const texts = [
'Learning never exhausts the mind',
'You teach best what you most need to learn',
'In youth we learn; in age we understand',
];
let arrayIndex = 0;
const type = () => {
if (charIndex < texts[arrayIndex].length) {
cursorEle.classList.remove('cursor__blink');
textEle.textContent += texts[arrayIndex].charAt(charIndex);
charIndex++;
setTimeout(type, 100);
} else {
cursorEle.classList.add('cursor__blink');
setTimeout(erase, 500);
}
};
同样,一旦当前文本被擦除干净,我们将等待 500 毫秒,然后再键入下一个文本。下面是函数 erase 如下所示的示例:
const erase = () => {
if (charIndex > 0) {
cursorEle.classList.remove('cursor__blink');
textEle.textContent = textEle.textContent.slice(0, charIndex - 1);
charIndex--;
setTimeout(erase, 100);
} else {
cursorEle.classList.add('cursor__blink');
arrayIndex++;
if (arrayIndex > texts.length - 1) {
arrayIndex = 0;
}
setTimeout(type, 500);
}
};
现在,是时候看最后的演示了!