ch是唯一能自动适配文字长度的css单位,因其基于等宽字体中“0”的宽度,1ch≈1个字符宽,配合steps(var(--char-count), end)和calc(var(--char-count) * 1ch)可实现精准打字动画。

必须用 ch 单位 + steps() + 等宽字体,否则“自动适配”就是空谈。硬写 steps(10, end) 或 width: 100% 都会错——文字一变,动画就卡在中间或漏字。
为什么 ch 是唯一能自动适配长度的单位
ch 表示当前字体中 “0” 字符的宽度,在等宽字体(如 monospace、Fira Code)下,1 个中文、英文、数字、标点 ≈ 1ch。这比 %(依赖父容器)、em(受嵌套 font-size 影响)稳定得多。
常见错误现象:
- 中文只显示一半 → 没设
font-family: monospace - 动画停在第 8 个字不动 →
width终点写成100%或20em,不是calc(var(--char-count) * 1ch) - 换行后动画乱跳 → 忘了加
white-space: nowrap
steps(N, end) 的 N 必须等于真实字符数
不是“大概估”,而是 "你好 ".length === 3 这种 JS 级别的精确计数:空格、换行符、全角标点都算。
静态写死 steps(12, end) 只适用于固定文案;动态场景必须靠 CSS 变量驱动:
- HTML 中显式传入:
<div class="typewriter" style="--char-count: 15; --duration: 1.5s">欢迎来到首页</div> -
@keyframes typing里终点必须是:to { width: calc(var(--char-count) * 1ch); } -
animation-timing-function必须写:steps(var(--char-count), end)—— 不能只写steps(1, end)再靠 JS 改,那样动画不会重播 - 字符数变更后,需强制重播:切换 class 或临时设
animation: none再恢复
光标闪烁必须独立于打字动画
把 border-right 光标和 width 动画塞进同一个 @keyframes,会导致光标随宽度拉伸、跳帧甚至消失。
正确做法:
- 光标用单独的
@keyframes blink-caret,只控制border-color透明/显色 - 动画函数必须是
step-end(不是steps(1, end)),否则闪烁节奏不准 - 别用
opacity控制光标——它会触发重绘,某些安卓 WebView 下闪烁失步
真正麻烦的不是写法,而是字体加载时机和中英文混排时的 ch 偏差。比如某些系统字体里中文“你”比“0”略宽,ch 就会少算 0.1~0.2 个字符——上线前务必在真机上测不同字号、不同语言组合下的裁切位置。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











