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

滚动触发多个CSS动画异常问题求助

解决多进度条视口触发动画的问题

核心问题拆解

你遇到的问题本质是动画逻辑没有和每个进度条的目标宽度绑定:要么多个观察者复用导致触发逻辑冲突,要么所有进度条共用了同一套动画参数,所以效果一致。

最简解决方案

用「单交叉观察器 + CSS变量」的组合,既避免观察者冗余,又能让每个进度条拥有独立的动画目标:

1. 调整HTML结构,给进度条标记目标宽度

给每个进度条添加自定义属性,存储它的目标填充百分比:

<div class="progress-wrap">
  <div class="progress" data-target="70"></div>
</div>
<div class="progress-wrap">
  <div class="progress" data-target="90"></div>
</div>
<div class="progress-wrap">
  <div class="progress" data-target="50"></div>
</div>

2. 用CSS变量控制动画

不用写多个重复的关键帧,只需要一套通用关键帧,通过变量动态替换目标宽度:

.progress-wrap {
  width: 80%;
  height: 24px;
  background: #e0e0e0;
  margin: 1.5rem 0;
  border-radius: 12px;
  overflow: hidden;
}

.progress {
  height: 100%;
  width: 0;
  background: #2196F3;
  border-radius: 12px;
  animation: fill 1.2s ease-out forwards;
  /* 默认变量值,避免异常 */
  --target-width: 0%;
}

@keyframes fill {
  to {
    width: var(--target-width);
  }
}

3. 单观察者处理所有元素

只用一个交叉观察器监听所有进度条,触发时给当前元素设置对应的CSS变量:

const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const bar = entry.target;
      // 从自定义属性取目标宽度,设置CSS变量
      bar.style.setProperty('--target-width', `${bar.dataset.target}%`);
      // 触发后停止监听该元素,防止重复动画
      observer.unobserve(bar);
    }
  });
}, { threshold: 0.2 });

// 批量给所有进度条添加观察
document.querySelectorAll('.progress').forEach(bar => {
  observer.observe(bar);
});

为什么这能解决你的问题

  • 单观察者避免了多实例的冲突问题,代码更简洁。
  • CSS变量让每个进度条的动画目标独立,不用写多套关键帧。
  • 触发动画后立即停止观察,确保每个进度条只动一次。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 19:40:16