ch单位最适合打字机动画,因其等于当前字体中“0”的宽度,等宽字体下每字符占1ch,确保逐字精准显现;而em受字符形状影响、px脱离字体上下文。

为什么 ch 单位比 em 或 px 更适合打字动画
因为 ch 表示“0”字符的宽度(等宽字体下 ≈ 一个字符宽度),动画用它做 width 过渡,能精准匹配逐字显示节奏;而 em 依赖字体大小、px 无法响应字体缩放或不同字体宽度变化,容易卡顿或错位。
实际使用时需确保父容器使用等宽字体(如 font-family: monospace, 'Courier New'),否则 ch 值会浮动——比如在系统默认的非等宽字体下,1ch 可能等于 “w” 的宽度而非 “i”,导致动画跳帧。
- 必须设置
white-space: nowrap防止换行打断动画 - 推荐搭配
overflow: hidden隐藏未显现部分 - 避免对中文混排文本直接用
ch控制宽度——中文字宽不等于1ch,此时应改用steps(n, end)配合字符数手动计算
steps() 函数里 end 和 start 到底该选哪个
打字效果必须用 steps(n, end):它让动画在每步结束时才跳变,视觉上是“字一个一个弹出”;若用 start,第一帧就显示全部内容,第二帧才开始删减,完全不符合预期。
参数 n 要等于文本字符数(注意空格、标点都算);常见错误是硬写死 steps(10, end) 却没校验字符串长度,导致动画提前结束或卡住最后一字。
- 动态内容需用 JS 计算:
element.textContent.length获取真实字符数 - 遇到 emoji(尤其是多码点 emoji,如 ??)时,
.length可能误判,建议用[...str].length处理 - CSS 中无法动态传参,所以静态文本可直接写死,动态文本必须靠 JS 注入对应
steps()值
完整 CSS 打字动画的关键声明顺序不能乱
动画生效依赖三要素叠加:宽度从 0 拉到目标值 + steps() 分帧 + monospace 字体锚定 ch。任意一环缺失都会失败。
.typing {
font-family: monospace;
white-space: nowrap;
overflow: hidden;
border-right: 2px solid #000; /* 可选光标 */
width: 0;
animation: type 3s steps(12, end), blink 0.75s step-end infinite;
}
@keyframes type {
to { width: 12ch; }
}
@keyframes blink {
50% { border-color: transparent; }
}
-
width: 0必须写在动画前,否则初始状态不是隐藏态 -
@keyframes中to { width: 12ch; }的数值必须和steps(12, end)严格一致 - 多个动画用逗号分隔,但
steps()只作用于紧邻它的那个动画(这里是type),别误以为它会影响blink
IE 和旧版 Safari 对 ch 与 steps() 的兼容性怎么兜底
IE 完全不支持 ch 单位,Safari ≤ 9 不支持 steps() 中的第二个参数(即 end)。真要兼容,得降级为 JS 驱动的字符循环 + setTimeout,或者用媒体查询隔离:
@supports (width: 1ch) and (animation-timing-function: steps(1, end)) {
.typing { /* 启用 CSS 方案 */ }
}
@supports not (width: 1ch), (animation-timing-function: steps(1, end)) {
.typing { /* 降级为 visibility: hidden + JS 显示 */ }
}
- 不要试图用
calc(1em * n)模拟ch——不同字体下1em宽度波动太大 - 移动端 iOS Safari 10+ 已支持完整
steps(n, end),但某些安卓 WebView 仍只认steps(n)(等价于steps(n, end)) - 真正难搞的是中英文混排且字体不固定场景:此时
ch失效,只能放弃纯 CSS 方案
实际项目里最常被忽略的,是字体加载完成前的闪动——@font-face 加载慢会导致动画开始时用回默认字体,ch 值突变。得用 font-display: optional 或监听 document.fonts.load() 延迟启动动画。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











