如何用单个动画实现多个Bootstrap进度条宽度动画并适配视口触发
解决方案
两个需求都可实现,具体优化方案如下:
核心优化点
- 利用CSS自定义属性实现单组
@keyframes适配所有不同宽度的进度条,无需重复定义多组动画 - 修复原JS中类名拼写错误,批量监听所有进度条容器,动态读取每个进度条的目标宽度适配多实例
改造后HTML
给每个进度条添加data-progress属性存储目标百分比,无需单独定义bar1~bar5类:
<div class="col-sm-6"> <h3 class="progress-title">SEO / SEM</h3> <div class="progress"> <div class="progress-bar" data-progress="60"> <div class="progress-value">60%</div> </div> </div> </div> <!-- 其余4个进度条仅需修改data-progress属性值和显示的百分比文本即可 -->
改造后CSS
仅保留1组通用动画,通过CSS变量动态适配不同宽度:
/* 通用动画触发类 */ .progress-bar.animated { animation: progressAnimate 3s ease-in-out; animation-fill-mode: both; } /* 全局唯一动画关键帧 */ @keyframes progressAnimate { 0% { width: 0; } 100% { width: calc(var(--target-width) * 1%); } }
改造后JS
批量监听所有进度条容器,动态注入宽度变量:
const observer = new IntersectionObserver(entries => { entries.forEach(entry => { const progressBar = entry.target.querySelector('.progress-bar'); // 读取当前进度条的目标宽度 const targetWidth = progressBar.dataset.progress; // 注入CSS变量 progressBar.style.setProperty('--target-width', targetWidth); if (entry.isIntersecting) { progressBar.classList.add('animated'); return; } // 如果不需要离开视口重置进度,可删除下面这行代码 progressBar.classList.remove('animated'); }); }); // 批量注册所有进度条容器到监听器 document.querySelectorAll('.progress').forEach(progress => { observer.observe(progress); });
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

