通道 · 23
文字内容
Text content · text-content让字符或数字本身变化;可见的滚动字符与可读的最终内容要分开。
文字也可以是动画通道:倒数、序号、乱码揭示,都在逐帧替换字符。若把每一帧的乱码交给读屏器,内容会不断被重复朗读;若计数宽度来回变化,旁边的排版会晃。视觉层和语义层分开,动完再发布最终值。
公式
scramble(text, p, {seed,time})
index < p·length → final character
otherwise → seeded flicker character
counter = round(lerp(start, end, p))参数
| 本页默认 | 成熟实现 | |
|---|---|---|
| progress | 0 → 1 | — |
| seed | 7 | —同一进度与时刻得到同一组字符。 |
| digits | 可切换等宽数字 | — |
| announcement | 只播报终值 | GSAP SplitText aria: auto 保留原文标签 |
怎样做好
- 把逐帧变化的字符层设为
aria-hidden,给容器固定的原文标签;结束后才通知最终结果。GSAP SplitText 的默认aria: auto会把原文设成父元素的aria-label。GSAP src/SplitText.ts:355, 373 - 计数器启用
font-variant-numeric: tabular-nums,让不同数字占相同宽度;站内 dimension 的编号也这么处理。www-motion/rewrite/dimension/index.html:64,70 - 乱码的最终字符应随进度固定,未揭示区域才闪烁;进度拖回去再拖回来,已到达的字符仍是原文。
- 只在真实值改变时更新计数文本;
cipher的章节计数跟当前页更新,而不是把全文每帧重新搭一遍。www-motion/rewrite/cipher/app.js:4
在我们的案例里
51 个案例直接改变文字内容。cipher 按当前章节改写计数,formation 打开详情时替换标题、客户和年份;这两种都是内容变化,和移动文字元素是不同通道。
出现在 51 个案例
参考实现 · basics.js
/** Deterministic scramble: characters left of the reveal front are final, the rest flicker. */
export function scramble(text, progress, { chars = '!<>-_\\/[]{}—=+*^?#', seed = 7, time = 0 } = {}) {
const front = progress * text.length;
let out = '';
for (let i = 0; i < text.length; i++) {
if (i < front || text[i] === ' ') { out += text[i]; continue; }
const r = mulberry32(seed + i * 31 + Math.floor(time * 20))();
out += chars[Math.floor(r * chars.length)];
}
return out;
}