You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中visibility:hidden与useEffect的异常问题排查

Next.js中visibility:hidden与文本拆分逻辑的冲突问题解决

问题现象

在Next.js项目中,尝试将组件内两个div的文本拆分为单个span元素时,遇到以下问题:

  • 未给父div设置visibility:hidden时,文本拆分功能正常,DOM结构符合预期
  • 添加visibility:hidden后,两个子div变成空内容,拆分逻辑失效
  • 尝试替换为useLayoutEffect也无改善,且该属性是后续动画效果必需的

相关代码

组件代码

const MyComponent = () => {
  const splitRef = useRef(null);

  useEffect(() => {
    const divs = splitRef.current.querySelectorAll("div");
    divs.forEach((item) => {
      let newInnerText = "";
      const letters = item.innerText.split("");
      letters.forEach((letter) => {
        newInnerText += `<span>${letter}</span>`;
      });
      item.innerHTML = newInnerText;
    });
  }, []);
  return (
    <>
      <div ref={splitRef} style={{ visibility: "hidden" }}>
        <div>CONTACT</div>
        <div>ABOUT</div>
      </div>
    </>
  );
};

页面引入代码

export default function IndexPage() {
  return (
    <div>
      <MyComponent />
    </div>
  );
}

DOM结构对比

  • 无visibility:hidden时:
<div>
  <div>
    <span>C</span><span>O</span><span>N</span><span>T</span><span>A</span><span>C</span><span>T</span>
  </div>
  <div>
    <span>A</span><span>B</span><span>O</span><span>U</span><span>T</span>
  </div>
</div>
  • 添加visibility:hidden后:
<div style="visibility:hidden">
  <div></div>
  <div></div>
</div>

问题原因

核心矛盾在于innerText的特性与Next.js的渲染机制:

  • innerText会受CSS可见性影响,且依赖元素的布局状态。当元素设置visibility:hidden后,在客户端Hydration阶段,浏览器可能因元素不可见而延迟布局计算,导致innerText无法获取到文本内容,最终拆分逻辑得到空数组,将子div的innerHTML设置为空。
  • 服务端渲染时,虽然初始HTML包含文本,但客户端Hydration时的布局处理逻辑会影响innerText的取值。

解决方案

将代码中的innerText替换为textContent即可解决问题。textContent直接读取DOM节点的原始文本内容,不受CSS可见性和布局状态的影响,无论元素是否可见都能正确获取文本。

修改后的组件代码

const MyComponent = () => {
  const splitRef = useRef(null);

  useEffect(() => {
    const divs = splitRef.current.querySelectorAll("div");
    divs.forEach((item) => {
      let newInnerText = "";
      // 改用textContent获取文本,不受visibility属性影响
      const letters = item.textContent.split("");
      letters.forEach((letter) => {
        newInnerText += `<span>${letter}</span>`;
      });
      item.innerHTML = newInnerText;
    });
  }, []);
  return (
    <>
      <div ref={splitRef} style={{ visibility: "hidden" }}>
        <div>CONTACT</div>
        <div>ABOUT</div>
      </div>
    </>
  );
};

修改后,即使父div设置了visibility:hidden,文本拆分逻辑仍能正常工作,DOM结构与无该属性时一致,同时保留后续动画所需的visibility设置。

内容的提问来源于stack exchange,提问作者Nas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 15:50:22