模式 · 29
拆字进场
Text split · text-split按字或词拆开标题做错峰动画,同时保留完整的可读名称。
逐字进场需要独立节点,但一串节点可能让辅助技术把标题读得支离破碎。让父节点保留原句作 aria-label,把视觉碎片设为 aria-hidden,动画就不会改变朗读内容。按字拆时还要考虑单词不要从中间换行。
公式
original = heading.textContent heading.ariaLabel = original parts = split(original, by) for part: span.text = part; span.ariaHidden = true delayᵢ = i × stagger
参数
| 本页默认 | 成熟实现 | |
|---|---|---|
| by | char / word | GSAP SplitText:chars, words, lines |
| aria | 父级保留原句 | GSAP aria: "auto" |
| stagger | 45 ms / part | — |
怎样做好
- 先保存原文再拆分。GSAP SplitText 的默认
aria: "auto"会把原文放到父节点的aria-label。GSAP src/SplitText.ts:355,373 - 视觉字片标记
aria-hidden,避免读屏器逐片重复朗读。GSAP src/SplitText.ts:149,373 - 按字动画时可在词外再包一层,避免同一个词从中间折行。www-motion/rewrite/lib/detail.js:43–45
在我们的案例里
19 个案例拆字或拆词。cardwall、liquid-type、type 等把文字变成可错峰的视觉单元;重写的详情标题还给每个词单独包层,避免字母在词中间换行。
出现在 19 个案例
参考实现 · basics.js
/**
* Split an element's text into spans for per-character animation without breaking
* screen readers: the parent keeps the real text as aria-label, the pieces are aria-hidden.
*/
export function splitText(el, by = 'char') {
const text = el.textContent;
el.setAttribute('aria-label', text);
el.textContent = '';
const parts = by === 'word' ? text.split(/(\s+)/) : Array.from(text);
return parts.map(part => {
if (/^\s+$/.test(part)) { el.append(part); return null; }
const span = document.createElement('span');
span.textContent = part; span.setAttribute('aria-hidden', 'true'); span.style.display = 'inline-block';
el.append(span); return span;
}).filter(Boolean);
}