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

NextJS中平滑滚动与过渡动画冲突,Chrome下无法正常工作

问题:NextJS横向平滑滚动在Chrome失效,Firefox正常

我用NextJS搭建个人网站,需要实现两个核心效果:

  • 横向列表的平滑滚动,点击元素时自动滚动到视口中心
  • 选中元素的放大transform动画

以下是简化实现代码,目前平滑滚动在Firefox中正常工作,但Chrome完全没有平滑效果:

原实现代码

React/JS部分

const items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

function ScrollContainer() {
  const [selectedIndex, setSelectedIndex] = React.useState(0)
  const itemRefs = React.useRef([])

  React.useEffect(() => {
    itemRefs.current = itemRefs.current.slice(0, items.length)
  }, [])

  const handleItemClick = (index) => {
    if (index !== selectedIndex) {
      setSelectedIndex(index)
      itemRefs.current[index].scrollIntoView({
        behavior: 'smooth',
        block: 'nearest',
        inline: 'center'
      })
    }
  }

  return (
    <div className="w-full h-screen flex items-center justify-center bg-gray-100">
      <div className="w-full max-w-3xl overflow-hidden">
        <div className="flex space-x-4 px-4 py-8 overflow-x-auto snap-x snap-mandatory scrollbar-hide">
          {items.map((item, index) => (
            <div
              key={item}
              ref={el => itemRefs.current[index] = el}
              className={`flex-shrink-0 w-32 h-32 flex items-center justify-center text-2xl font-bold text-white rounded-lg snap-center transition-all duration-300 ease-in-out cursor-pointer
                ${index === selectedIndex ? 'bg-blue-500 scale-110' : 'bg-gray-400 scale-100 hover:bg-gray-500'}`}
              onClick={() => handleItemClick(index)}
            >
              {item}
            </div>
          ))}
        </div>
      </div>
    </div>
  )
}

ReactDOM.createRoot(
  document.getElementById("root")
).render(
  <ScrollContainer />
);

HTML依赖部分

<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>

问题原因

Chrome的滚动引擎在处理scrollIntoView({behavior: 'smooth'})时,如果目标元素同时应用了transform: scale()这类变换,会出现逻辑冲突——元素的几何变换会干扰滚动动画的位置计算,导致平滑滚动直接跳过,变成瞬间定位。而Firefox的滚动引擎对这种场景的兼容性更好,所以能正常触发平滑动画。

修复方案

方案1:分离滚动目标与变换元素(推荐)

将元素的滚动定位和缩放动画分离到两个层级:外层div作为滚动目标(无transform),内层div负责样式和缩放。这样Chrome的滚动动画不会被transform干扰。

修改后的核心JSX部分:

{items.map((item, index) => (
  <div
    key={item}
    ref={el => itemRefs.current[index] = el}
    className={`flex-shrink-0 w-32 h-32 flex items-center justify-center cursor-pointer snap-center`}
    onClick={() => handleItemClick(index)}
  >
    <div className={`w-full h-full flex items-center justify-center text-2xl font-bold text-white rounded-lg transition-all duration-300 ease-in-out
      ${index === selectedIndex ? 'bg-blue-500 scale-110' : 'bg-gray-400 scale-100 hover:bg-gray-500'}`}>
      {item}
    </div>
  </div>
))}

方案2:延迟触发缩放动画

在触发滚动后,延迟设置选中状态,确保滚动动画完成后再应用缩放变换。调整handleItemClick函数:

const handleItemClick = (index) => {
  if (index !== selectedIndex) {
    // 先触发滚动
    itemRefs.current[index].scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
      inline: 'center'
    })
    // 延迟300ms(与transition时长一致)设置选中状态
    setTimeout(() => {
      setSelectedIndex(index)
    }, 300)
  }
}

验证效果

两种方案都能解决Chrome中平滑滚动失效的问题,同时保留选中元素的放大动画。方案1无需额外JS逻辑,结构更清晰,推荐使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 06:29:53