单行打字机效果
这里借助了 animation 的 steps 的特性实现,也就是逐帧动画。
从左向右和从上向下原理是一样的,以从左到右为例,假设我们有 26 个英文字符,我们已知 26 个英文字符组成的字符串长度,那么只需要设定一个动画,让它的宽度变化从 0-100%经历 26 帧即可,配合 overflow:hidden,steps 的每一帧即可展示一个字符。 划重点:这里是有技巧的,这样设置需要每次出来的字是等宽的,css 中,ch 单位表示”0”的宽度。如果字体恰巧又是等宽字体,即每个字符的宽度是一样的,此时 ch 就能变成每个英文字符宽度,那么 26ch 其实就是整个字符串的长度。 利用这个特性,配合 animation 的 steps,单行打字机代码如下:
<h1 > Pure CSS TyPing animation.</h1 > h1 {
font-family: monospace;
width: 26ch;
white-space: nowrap;
overflow: hidden;
animation: typing 3s steps(26, end);
}
@keyframes typing {
0 {
width: 0;
}
100% {
width: 26ch;
}
}
上述打字机效果有下面两个局限: 1.限制了等宽字体,正常的页面一般没有用等宽字体,而是用常见的衬线与非衬线字体。 2.限制了单行文本,实际效果,GPT 的输出内容都是大段大段的,单行肯定无法满足需求,我们需要一种光标效果能适配多行文本的方式。
###用 background 实现多行光标效果 首先,需要将光标输出的内容动态生成。
<template>
<div ref="contentElement"> {{displayedText}} </div>
</template>
<script setup>
import {ref, onMounted, onUnmounted} from 'vue';
const text = 'Lorem ipsum dolor sit amet consectetur elit ....'
const displayedText = ref('')
let index = ref(0)
let timeoutId = null;
const addNextCharacter = () => {
if(index.value < text.length) {
displayedText.value +=text[index.value];
index.value++;
timeoutId = setTimeOut(addNextCharacter,Math.random()*150+30);
}
};
onMounted(() => {
addNextCharacter();
})
onUnmounted(() => {
//清除定时器,防止内存泄漏
if(timeoutId) clearTimeout(timeoutId)
})
</script>
光标在行尾闪烁效果
在 display: inline 的 标签下,动画效果是以行为单位进行变换的。
针对这个特性,我们将我们的文本容器,改为 display: inline,然后给他设置一个特殊的背景,前 100% - 2px 宽度为一个颜色,最后 2px 为一个颜色。
完整代码如下:
:root {
--pointerColor: #000;
}
p {
display: inline;
background: linear-gradient(
90deg,
transparent,
transparent calc(100% - 2px),
var(--pointerColor) calc(100% - 2px),
var(--pointerColor)
);
animation: colorChange 0.8s linear infinite;
padding-right: 4px;
}
@keyframes colorChange {
0%,
50% {
--pointerColor: #000;
}
50%,
100% {
--pointerColor: transparent;
}
}
除上述方法外,还可以用 animation 的 blink 效果来实现,具体代码如下:
animation: {
blink: 'blink 1.2s infinite steps(1, start)'
}
keyframes: {
blink: {
'0%, 100%': { 'background-color': 'currentColor' },
'50%': {
'background-color': 'transparent'
},
},
}