CSS——文字打字机效果
本文通过纯 CSS 实现文字的打字机效果,然后借助 JS 实现了扩展。
typewriter
基本思路
使用伪元素覆盖原文字,并且使用伪元素模拟闪烁的光标效果。
具体流程
首先是一些基本的设置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文字打字机效果</title>
<style>
* {
padding: 0;
margin: 0;
}
body {
/* 防止宽度过小,导致 h1的宽度与视口的最小宽度一致,以至于效果出现差错 */
min-width: fit-content;
width: 100vw;
height: 100vh;
background-color: hsl(280, 50%, 30%);
display: flex;
justify-content: center;
align-items: center;
/* 设置等宽字体 */
font-family: monospace;
/* 不要滚动条 */
overflow: hidden;
}
#h1 {
position: relative;
color: #fff;
text-align: center;
font-size: 2.5rem;
letter-spacing: .2em;
text-transform: uppercase;
/* 防止文字换行 */
text-wrap: nowrap;
/* 加载完成之后隐藏后面的输入 */
overflow: hidden;
}
#h1::before,
#h1::after {
content: "";
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background-color: hsl(280, 50%, 30%);
}
</style>
</head>
<body>
<h1 id="h1">I'm lazy-sheep-king!</h1>
</body>
</html>
#h1::before
遮住原文字,然后设置关键帧逐步显示,#h1::after
用于表示光标。
这里有一些需要注意的点:
首先是 body
设置为 min-width: fit-content;
,这里是防止缩放视口导致视口宽度小于原来文本的宽度时,文本的宽度也会跟着缩小为视口的宽度;
然后是设置等宽字体 font-family: monospace;
,这个是关键,每一步的步长就是每个字母的宽度;
此外是 h1
标签的 ext-wrap: nowrap;
,这里是防止宽度过小导致文字换行;
最后是 h1
标签的 overflow: hidden;
,这个可有可无,如果加上,那么最后的光标就会隐藏,如果不加,那么文字加载完成之后的光标就会继续闪烁。
设置关键帧
首先设置移动关键帧:
#h1::before {
animation: typewriter 5s steps(20) forwards;
}
#h1::after {
width: 5px;
border-radius: 1em;
background-color: hsl(60, 100%, 35%);
animation: typewriter 5s steps(20) forwards
}
@keyframes typewriter {
to {
left: 100%;
}
}
首先解释 steps(20)
,效果为该动画分为多少步完成,一步一顿,因为有20个字符,所有就分为20步完成。
然后是 animation-fill-mode: forwards
,这个是动画结束之后,元素的状态,这里停留到最后一帧。
设置光标闪烁帧
#h1::after {
width: 5px;
border-radius: 1em;
background-color: hsl(60, 100%, 35%);
animation: typewriter 5s steps(20) forwards,
flashing 0.25s infinite alternate;
}
@keyframes flashing {
to {
opacity: 0;
}
}
通过改变透明度,表示光标的闪烁效果。
同一个元素可以添加多个动画效果,用逗号“,”隔开。
扩展性
为了增强扩展性,可以使用js
进行一些处理。
<script>
// 获取标签
const h1 = document.querySelector('#h1');
// 获取文本长度
const length = h1.innerHTML.length;
// 使用自定义属性变量传递到 CSS中
h1.style.setProperty('--length', length);
</script>
这样我们动态计算文本的长度,并使用自定义属性变量传递到 CSS中,将steps(20)
中的参数换位var(--length)
,但需要注意的是,即使是等宽的字体,其中文和英文的宽度还是有区别的,这里仅考虑为纯英文或纯中文的情况(如果中英文混合的话,可以考虑使用<span>标签包裹每个单独的单词/汉字,然后设置统一的宽度,最后使用js添加与计算)。
结语
创作不易,谢谢支持;如有错误,恳请指出,希望与大家共同进步!
源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文字打字机效果</title>
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
/* 防止宽度过小,导致 h1的宽度与视口的最小宽度一致,然后使效果出现差错 */
min-width: fit-content;
width: 100vw;
height: 100vh;
background-color: hsl(280, 50%, 30%);
display: flex;
justify-content: center;
align-items: center;
/* 设置等宽字体 */
font-family: monospace;
/* 不要滚动条 */
overflow: hidden;
}
#h1 {
position: relative;
color: #fff;
text-align: center;
font-size: 2.5rem;
letter-spacing: .2em;
text-transform: uppercase;
/* 防止文字换行 */
text-wrap: nowrap;
/* 加载完成之后隐藏后面的输入 */
overflow: hidden;
}
#h1::before,
#h1::after {
content: "";
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background-color: hsl(280, 50%, 30%);
}
#h1::before {
animation: typewriter 5s steps(20) forwards;
}
#h1::after {
width: 5px;
border-radius: 1em;
background-color: hsl(60, 100%, 35%);
animation: typewriter 5s steps(20) forwards,
flashing 0.25s infinite alternate;
}
@keyframes typewriter {
to {
left: 100%;
}
}
@keyframes flashing {
to {
opacity: 0;
}
}
</style>
</head>
<body>
<h1 id="h1">I'm lazy-sheep-king!</h1>
<script>
// 获取标签
const h1 = document.querySelector('#h1');
// 获取文本长度
const length = h1.innerHTML.length;
// 使用自定义属性变量传递到 CSS中
h1.style.setProperty('--length', length);
console.log(length);
</script>
</body>
</html>