直接用 content + ::after 无法实现流畅打字效果,因 content 不支持逐字符动画且不可过渡;应改用 width 或 clip-path 配合 steps() 控制遮罩,文字写在 html 内,光标单独用伪元素实现。

为什么直接用 content + ::after 写打字效果会卡顿或跳字
因为 content 属性本身不支持逐字符动画,CSS 无法对伪元素的内容做“字符串切片”;你看到的所谓“打字”效果,本质是靠 keyframes 控制 width 或 clip-path 做视觉遮罩,不是真正在往里塞字符。如果误以为可以动态改 content 的值来模拟输入,就会发现它根本不响应动画帧——content 是非过渡属性,也不能被 @keyframes 驱动。
实操建议:
- 用
white-space: nowrap和overflow: hidden锁定单行显示 - 动画目标必须是可过渡的属性:优先选
width(配合inline-block)或clip-path(更平滑,但 IE 不支持) - 文字内容写在 HTML 元素内,不要试图塞进
::after的content里做动态拼接 - 若坚持用
::after,只让它承载光标(如content: "|"),而非文字主体
用 width + steps() 实现精准逐字节奏
steps(6, end) 这类缓动函数才是控制“一个字一停”的关键,不是靠时间均分。假设你要打 6 个字,就设 steps(6, end),动画总时长除以 6 才是单字停留时间。用 linear 会滑动模糊,看不出字形。
示例结构:
<div class="typewriter">Hello World</div>
CSS 片段:
.typewriter {
font-family: monospace;
white-space: nowrap;
overflow: hidden;
border-right: 2px solid #000;
width: 0;
animation:
typing 3.2s steps(11, end),
blink-caret .75s step-end infinite;
}
@keyframes typing {
from { width: 0 }
to { width: 11em } /* 手动估算字符宽度,或用 ch 单位 */
}
@keyframes blink-caret {
from, to { border-color: transparent }
50% { border-color: #000 }
}
注意点:
-
11em是粗略值,实际应按字体和字号测——更稳妥用ch:比如width: 11ch(1ch ≈ 一个 0 的宽度) -
steps(11, end)中的11必须严格等于字符数(空格也算),否则最后一字闪一下就消失 - 动画结束后加
animation-fill-mode: forwards,否则width会弹回 0
clip-path 方案比 width 更可靠,但要注意兼容性
clip-path: inset(0 100% 0 0) 从右往左裁剪,配合 animation 改变右侧偏移量,能避免字体度量误差,也不依赖 em/ch 估算。但 Safari 旧版、IE 完全不支持,移动端 Android 4.4– 最好降级。
核心写法:
@keyframes clip-typing {
from { clip-path: inset(0 100% 0 0) }
to { clip-path: inset(0 0 0 0) }
}
.typewriter-clip {
clip-path: inset(0 100% 0 0);
animation: clip-typing 3.2s steps(11, end) forwards;
}
使用条件:
- 必须确保父容器有
overflow: visible,否则clip-path裁剪会被外层截断 - 不能和
transform同时触发硬件加速,否则某些 Chrome 版本会闪烁 - 想兼容老浏览器?加一层
@supports (clip-path: inset(0)) { ... }包裹,并在外部写width备用方案
光标闪烁怎么和打字节奏同步而不抢戏
单独写一个 blink-caret 动画很容易和打字不同步——比如打字结束光标还在狂闪,或者打完字光标立刻消失。正确做法是让光标动画时长 = 打字总时长,并用 step-end 控制闪烁时机。
关键参数:
- 光标动画周期设为打字总时长的约 1/4~1/3(例如打字 3.2s,光标用 0.75s),并
infinite - 必须用
step-end,否则透明→不透明过程会渐变,失去“数字终端”感 - 如果打字动画用了
forwards,光标要额外加animation-delay: 3.2s来等文字打完再开始稳定闪烁 - 别用
border-right模拟光标——它会随字体变化抖动;推荐用box-shadow或绝对定位伪元素
真正难调的是多行文本场景:每行字数不同,steps() 数量就得分别算,没法共用一套动画。这时候不如交给 JS 控制,CSS 只负责光标和基础入场。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











