如何在 Framer Motion 中实现逐字动画并保留原始空格

5次阅读

如何在 Framer Motion 中实现逐字动画并保留原始空格

本文介绍如何在使用 framer motion 对文本进行逐字(letter-by-letter)动画时,准确保留单词间的空格,避免因字符串拆分导致的空格丢失问题。

本文介绍如何在使用 framer motion 对文本进行逐字(letter-by-letter)动画时,准确保留单词间的空格,避免因字符串拆分导致的空格丢失问题。

在构建精细的文字动效时,开发者常通过 text.split(”) 将字符串转为字符数组,再用 motion.div 逐项渲染并添加动画。但该方法存在一个隐蔽陷阱:HTML 默认会合并连续空白符(包括空格、换行、制表符),且

是块级元素,若未显式控制空白处理行为,空格字符(’ ‘)虽被正确拆分并传入,却在渲染时被浏览器忽略或折叠——最终呈现为无间隙的紧凑文本(如 ‘WebDeveloper’)。

✅ 正确方案:保留空格的两种可靠方式

方案一:使用 CSS white-space: pre(推荐)

为每个 motion.div 设置 white-space: pre,强制浏览器按源码保留空格与换行。但需注意:JSX 中 {char} 前后默认存在换行和缩进,会额外引入空白节点。因此必须移除 JSX 换行与空格,并确保 motion.div 内仅包裹纯字符:

import { motion } from 'framer-motion';  type Props = {   text: String; };  function AnimatedText({ text }: Props) {   const characters = text.split('');    return (     <div className="flex">       {characters.map((char, index) => (         <motion.div           key={index}           className="inline-block"           style={{ whiteSpace: 'pre' }} // ? 关键:保留空格           initial={{ opacity: 0, y: 15 }}           animate={{ opacity: 1, y: 0 }}           transition={{ delay: 0.04 * index }}         >           {char}         </motion.div>       ))}     </div>   ); }  export default AnimatedText;

? 提示:添加 className=”inline-block” 可避免 div 默认块级行为干扰行内布局;whiteSpace: ‘pre’ 确保空格字符(U+0020)被渲染为可见空白。

方案二:将空格替换为  (非破坏性兼容方案)

若无法修改样式或需兼容更旧环境,可在拆分后预处理字符:将普通空格 ‘ ‘ 替换为 HTML 不间断空格实体(’u00A0’),它始终占据宽度且不会被折叠:

const characters = text.split('').map(char =>   char === ' ' ? 'u00A0' : char );

然后直接渲染,无需额外 CSS:

{characters.map((char, index) => (   <motion.div     key={index}     initial={{ opacity: 0, y: 15 }}     animate={{ opacity: 1, y: 0 }}     transition={{ delay: 0.04 * index }}   >     {char}   </motion.div> ))}

⚠️ 注意事项与最佳实践

  • 避免使用   字符串字面量:直接写   在 JSX 中无效,必须用 Unicode 转义 u00A0 或 String.fromCharCode(160);
  • 性能考量:对超长文本(如 >500 字符),逐字符渲染可能触发大量 dom 节点,建议结合 React.memo 或节流策略;
  • 语义化补充:若动画文本具有标题语义,可在外层包裹

    并设置 aria-label={text},确保无障碍访问;

  • 响应式适配:空格宽度受字体、字号影响,建议搭配 font-variant-numeric: tabular-nums 等属性保持等宽一致性(尤其数字场景)。

通过上述任一方式,你均可精准还原 ‘Web Developer’ 的原始间距,并赋予每个字符独立、可控的进入动画——既保持设计意图,又不失工程健壮性。

text=ZqhQzanResources