ch单位配合steps()能精准模拟打字机效果,因ch基于等宽字体中“0”的宽度实现字符级精度,steps(n, end)控制逐帧跳变,clip-path配合calc(100% – 1ch)实现从左到右逐字显示,需确保n等于字符数且使用monospace字体。

为什么 ch 单位 + steps() 能模拟打字机效果
因为 ch 是当前字体中 “0” 字符的宽度,它天然适配等宽字体下的单字符占位;而 steps(1, end) 能让动画在每一帧只跳变一次、不缓动,配合 width 或 clip-path 截断,就形成逐字“打出”的视觉节奏。用 % 或 em 都做不到这种字符级精度——尤其当文本含中文或变宽字符时,ch 反而比 ch 数值更稳定(前提是用等宽字体)。
- 必须设
font-family: monospace或明确指定等宽字体(如"SFMono-Regular", Consolas, "Liberation Mono"),否则ch行为不可控 -
steps(N, end)的N要等于文本字符数,动态内容需用 js 计算并注入 css 变量或内联animation-timing-function - 别用
opacity或visibility模拟——它们不触发重排,无法实现“从左到右逐字出现”的空间感
用 clip-path 实现兼容性更好的逐字显示
width + overflow: hidden 看似简单,但在 flex/Grid 容器里容易塌陷或触发意外换行;clip-path 直接裁剪渲染区域,不干扰布局流,且支持从 inset(0 100% 0 0) 动态缩进,更贴近真实打字逻辑。
- 关键写法:
clip-path: inset(0 <code>calc(100% - 1ch)0 0) → 随动画进度逐步减小右侧裁剪宽度 - 起始状态必须是
inset(0 100% 0 0)(完全隐藏),终点是inset(0 0 0 0)(完全显示) - safari 15.4+ 才支持
clip-path动画中的calc(),旧版需降级为 JS 控制clipPath内联样式
steps() 的步数错位:常见错误现象与修复
动画播完但最后 1–2 个字没显示,或开头多闪一下——基本是 steps() 步数和字符数对不上。CSS 动画的 steps(N) 实际会把动画总时长均分成 N 段,每段结束时跳变一次,共 N 次跳变,覆盖 N+1 个状态点(含初始态)。所以若文本有 12 个字符,应设 steps(12),而非 steps(11) 或 steps(12, start)。
- 调试技巧:临时加
animation-duration: 12s,每秒看一个字,直观验证步数是否匹配 - 中文混排时,用
textContent.Length计算长度即可(UTF-16 编码下,大部分中文字符占 1 个length单位) - 避免用
innerText——它会忽略空格和换行,导致字符数偏少
性能陷阱:不要在长文本上直接用纯 CSS 打字机
超过 50 字的段落,用 steps(N) 会让浏览器为每一帧生成独立样式快照,触发大量重排重绘,低端设备明显卡顿。此时应改用 requestAnimationFrame + substring() 逐帧更新文本内容,CSS 只负责基础过渡(如淡入)。
立即学习“前端免费学习笔记(深入)”;
- 临界点很实际:ios Safari 在
steps(60)时已有 16ms 以上 layout 时间,android chrome 更敏感 - 折中方案:CSS 做首屏 1–2 行打字,后续内容用 JS 分块加载 + 插入,避免一次性渲染整段
- 绝对不要给
clip-path动画加will-change: clip-path——它在多数移动端反而降低性能
真正难的不是写出第一个能动的版本,而是让第 100 个用户在千元机上也看不出卡顿。字符数、字体、运行环境,三者缺一都会让 ch 和 steps() 的理论精度落空。