如何实现长度无关、移动速度恒定的CSS进度条?
实现宽度无关的恒定速度不确定进度条
我用以下代码实现了一个不确定进度条,但发现它的移动速度会随容器宽度变化——容器越长,动画在固定时长内需要跨越的实际距离越大,视觉上速度就越快。我希望这个进度条既能用于网站顶部的全局宽进度条,也能用于组件内的小型进度条,因此需要解决速度恒定的问题。
原实现代码
CSS
.progress-bar-short, .progress-bar-long { animation-duration: 2.2s; animation-iteration-count: infinite; animation-delay: 200ms; will-change: left, right; } .progress-bar-short { animation-name: indeterminate-short-ltr; } .progress-bar-long { animation-name: indeterminate-ltr; } @keyframes indeterminate-ltr { 0% { left: -90%; right: 100%; } 60% { left: -90%; right: 100%; } 100% { left: 100%; right: -35%; } } @keyframes indeterminate-short-ltr { 0% { left: -200%; right: 100%; } 60% { left: 107%; right: -8%; } 100% { left: 107%; right: -8%; } }
HTML
<div style="position: relative; width: 100%; height: 4px;"> <div class="progress-bar-long" style="left: 0%; right: 100%; top: 0; bottom: 0; position: absolute; background-color: red;"></div> <div class="progress-bar-short" style="left: 0%; right: 100%; top: 0; bottom: 0; position: absolute; background-color: red;"></div> </div>
解决方案:基于固定速度的动态动画时长
核心思路是让动画时长随容器宽度动态计算,确保进度条的移动速度(像素/秒)恒定。具体实现如下:
修改后的CSS
/* 定义全局默认变量 */ :root { --speed: 300px/s; /* 恒定速度:每秒移动300像素 */ --container-width: 100%; /* 默认容器宽度,可通过内联样式覆盖 */ } .progress-bar-short, .progress-bar-long { animation-iteration-count: infinite; animation-delay: 200ms; animation-timing-function: linear; /* 强制匀速移动 */ will-change: transform; /* 优化动画性能 */ position: absolute; top: 0; bottom: 0; background-color: red; } /* 长进度条:总移动比例为190%(从-90%到100%) */ .progress-bar-long { width: 90%; animation-name: indeterminate-ltr; animation-duration: calc( (1.9 * var(--container-width)) / var(--speed) ); } /* 短进度条:总移动比例为307%(从-200%到107%) */ .progress-bar-short { width: 100%; animation-name: indeterminate-short-ltr; animation-duration: calc( (3.07 * var(--container-width)) / var(--speed) ); } /* 改用transform实现位移,性能更优且计算更直观 */ @keyframes indeterminate-ltr { 0% { transform: translateX(-100%); } 60% { transform: translateX(-100%); } 100% { transform: translateX(calc(100% / 0.9)); /* 等价于从-90%位移到100%的总距离 */ } } @keyframes indeterminate-short-ltr { 0% { transform: translateX(-200%); } 60% { transform: translateX(calc(107% + 8%)); /* 对应原动画的目标位置 */ } 100% { transform: translateX(calc(107% + 8%)); } }
修改后的HTML(不同宽度容器示例)
<!-- 全局宽进度条 --> <div style="position: relative; width: 100%; height: 4px; --container-width: 100vw;"> <div class="progress-bar-long"></div> <div class="progress-bar-short"></div> </div> <!-- 小型组件进度条 --> <div style="position: relative; width: 200px; height: 4px; --container-width: 200px;"> <div class="progress-bar-long"></div> <div class="progress-bar-short"></div> </div>
关键说明
animation-timing-function: linear:确保动画全程匀速,避免默认缓动效果导致的速度波动- 动态计算
animation-duration:通过calc()将总移动距离除以固定速度,保证不同宽度容器下的移动速度一致 - 改用
transform: translateX():相比修改left/right,transform动画的性能更优,且位移计算更直观
内容的提问来源于stack exchange,提问作者Mitar
相关产品推荐
相关产品推荐

