纯css打字机效果最稳方案是ch单位+steps()动画,需满足等宽字体、steps(n,end)中n等于字符数、width终点为calc(--char-count*1ch)三条件;ch比%或em稳定因直接绑定“0”字宽且等宽字体下各字符≈1ch。

纯 CSS 实现打字机效果,ch 单位 + animation 是目前最可控、最免维护的方案,但必须满足三个硬性条件:容器用等宽字体、steps(N, end) 的 N 与字符数完全一致、width 终点写成 calc(var(--char-count) * 1ch) —— 少一个条件,动画就卡顿或漏字。
为什么 width 动画配 ch 单位比百分比或 em 更稳
width: 100% 在响应式布局中会随父容器缩放,导致 steps() 帧数与实际字符显示不匹配;em 受 font-size 继承链影响,嵌套深了容易偏移;而 ch 直接绑定当前字体下 "0" 的渲染宽度,在等宽字体(如 monospace、Fira Code)中,1 个中文/英文/数字/标点 ≈ 1ch(误差可忽略)。
常见错误现象:
– 中文显示一半就被裁掉 → 没设 font-family: monospace
– 光标停在文字中间不动 → width 终点写成了 100% 或 10em,不是 12ch
– 动画开头闪一下全字 → 忘了加 overflow: hidden
- 必须显式声明
font-family: monospace或具体等宽字体名,不能只靠浏览器默认 -
ch对 Emoji 和某些连字(如fi)仍可能偏差,若内容含大量 Emoji,建议改用 JS 控制textContent插入 -
white-space: nowrap必须加,否则换行会破坏ch累加逻辑
如何用 CSS 变量动态控制字符数和时长
静态写死 steps(12, end) 和 width: 12ch 不可复用。真正可维护的方式是把字符数和总时长抽成变量:--char-count 控制步数与终点宽度,--duration 控制总耗时。
关键点:
– animation 声明里必须写 steps(var(--char-count), end),不能只写 steps(1, end) 再靠 JS 改——那样不会重播动画
– @keyframes 里的 to { width: calc(var(--char-count) * 1ch) } 是唯一能响应变量变化的写法
– 字符数变更后,需强制重播:通过 JS 切换 class 或 toggle animation: none 后再恢复
- HTML 中直接写:
<div class="typewriter" style="--char-count: 7; --duration: 2.1s">Hello!</div> - 如果文本含空格或中文,
--char-count必须包含它们("你好 ".length === 3) - 时长建议 ≥
0.05s × --char-count,低于这个值人眼无法分辨单字出现过程
光标闪烁为什么必须用 step-end,且独立于 typing 动画
border-right 光标不能和 typing 动画共用一个 @keyframes,否则光标会随宽度变化“拉伸”或“跳帧”。它必须是独立、瞬时切换的动画。
错误写法:animation: typing 3s steps(12, end), blink-caret 0.75s linear infinite → linear 会让光标缓慢变色,失去机械感
正确写法:animation: typing 3s steps(12, end), blink-caret 0.75s step-end infinite
-
step-end表示“在每步结束时才切换”,视觉上就是稳定闪烁,无过渡 - 不要用
opacity做光标动画——部分浏览器对opacity的step-end支持不佳 - 若需光标为方块(非竖线),可用
::after+content: ""+width: 0.5ch,同样配step-end
最易被忽略的一点:当文本动态更新(比如从 “Loading…” 切到 “Done!”)时,--char-count 变了,但浏览器不会自动重播 animation。你得手动触发重播,比如用 el.style.animation = "none" 瞬间清空,再设回原值——这步不做,新文本永远卡在旧长度。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











