用 width + transition 实现动态进度条需子元素设 width: 0%、height: 100%、display: block,父容器 overflow: hidden;transition 必写于子元素且指定 width,js 更新时 style.width = ‘65%’ 并防超 100%。

用 width + transition 实现基础动态进度条
核心就是控制一个子元素的 width 从 0% 变到目标值,配合 transition 让变化平滑。父容器设为固定高度和背景(表示轨道),子元素设背景色、height: 100%、width: 0%,再通过 class 或内联样式改 width 即可触发动画。
关键点:transition 必须写在子元素上,且要明确指定过渡属性(推荐写 width 0.4s ease,不建议用 all);父容器需设 overflow: hidden,否则宽度超出会溢出显示。
常见错误:
- 忘记给子元素设
display: block(默认 inline 元素不响应width) -
transition写在父容器上,无效 - 初始
width写成0(无单位),应为0%
如何用 JS 动态更新进度条的 width
直接操作 dom 元素的 style.width 是最直接的方式,比如 bar.style.width = '65%'。注意单位必须带 %,否则无效。
立即学习“前端免费学习笔记(深入)”;
使用场景:表单上传、步骤引导、加载状态反馈等。若进度由异步过程驱动(如 fetch 上传),需确保 DOM 元素已挂载,避免 Cannot set Property 'width' of NULL。
小技巧:
- 用
math.min(progress, 100)防止超 100% - 配合
requestAnimationFrame控制高频更新更流畅(如实时上传进度) - 若需支持 IE10+,
transition可加-ms-前缀,但现代项目通常不需要
transition 失效的几个典型原因
不是所有 width 变化都会触发过渡动画。常见失效情形:
- 初始
width和目标width都是auto或无单位数值(如50) - 元素未触发重排(例如通过
getComputedStyle强制读取后立即写入,或用setTimeout分开两帧) - 父容器或自身有
display: none,导致元素未渲染,后续设置width不触发 transition - css 中
transition被更具体的规则覆盖(如被另一个 class 的transition: none覆盖)
验证方法:打开 DevTools,在 Elements 面板中手动修改元素的 style.width,看是否平滑变化——能动说明 CSS 没问题,问题出在 JS 更新时机或方式上。
兼容性与性能注意事项
width + transition 方案在所有现代浏览器(chrome/firefox/safari/edge)中完全支持,包括 ios Safari 9+。唯一要注意的是:当进度条频繁更新(如每 50ms 一次),直接改 style.width 可能引发重排抖动。
优化建议:
- 对高频率进度(如视频播放器),优先考虑
transform: scaleX()替代width(它只触发合成,不触发布局) - 避免在
transition中混用width和transform,会导致浏览器无法优化图层 - 移动端低端设备上,
ease-out比cubic-bezier(0.4, 0, 0.2, 1)更稳妥
真正容易被忽略的是:progress 条的语义化。纯 CSS 进度条对屏幕阅读器不友好,如需无障碍支持,得额外加 role="progressbar" 和 aria-valuenow 等属性,仅靠视觉动效是不够的。