如何实现带进度动画的垂直时间轴:线条绘制时同步切换节点状态
垂直时间轴动画实现思路
核心逻辑拆分
- 把整体动画拆成两个独立控制的单元:竖线进度绘制动画、节点状态切换动画
- 提前预处理所有条目数据:统计所有
status=true的条目总高度,作为整个进度动画的总长度基准
竖线绘制动画实现
- 优先用CSS实现更流畅:给进度竖线设置初始
height: 0,或者用clip-path: inset(100% 0 0 0)做顶部裁剪,动画触发时将属性更新为总高度/clip-path: inset(0 0 0 0),搭配线性缓动和固定时长即可实现从上到下逐步绘制的效果 - 如果是节点间分段的独立竖线,可以给每段
status=true的竖线按顺序设置递增的动画延迟,前一段播放完成后再启动下一段,更符合逐段推进的视觉效果
节点状态切换实现
- 先计算每个已完成节点距离时间轴顶部的偏移量,除以总进度长度得到该节点对应的进度百分比
- 状态切换触发可以选两种方案:
- 用
requestAnimationFrame实时监听进度动画的当前进度,进度超过对应节点百分比时触发样式切换 - 按节点进度百分比计算对应延迟时间,用
setTimeout触发,刚好和竖线走到节点的时间对齐
- 用
- 对勾样式切换用CSS transform实现即可:初始对勾设置
scale(0)+opacity(0),触发时改为scale(1)+opacity(1),搭配短时长的弹性缓动,视觉效果更自然
核心代码参考
可直接在现有代码基础上调整:
/* 进度竖线基础样式 */ .timeline-progress { position: absolute; left: 12px; top: 0; width: 4px; background: #1677ff; height: 0; transition: height 3s linear; } /* 已完成节点样式 */ .timeline-item.done .node-circle { background: #1677ff; border-color: #1677ff; } .timeline-item .check-icon { transform: scale(0); opacity: 0; transition: all 0.2s ease-out 0.05s; } .timeline-item.done .check-icon { transform: scale(1); opacity: 1; }
// 动画启动逻辑 const runTimelineAnimation = () => { // 动态计算总进度高度 const doneItemList = Array.from(document.querySelectorAll('.timeline-item[status="true"]')) const totalProgressHeight = doneItemList.at(-1).offsetTop // 启动竖线绘制动画 document.querySelector('.timeline-progress').style.height = `${totalProgressHeight}px` // 批量设置节点状态切换延迟 doneItemList.forEach(item => { const delayTime = (item.offsetTop / totalProgressHeight) * 3000 // 3000对应CSS中3s总动画时长 setTimeout(() => item.classList.add('done'), delayTime) }) }
优化提示
- 如果条目高度不固定,用
getBoundingClientRect()动态计算节点位置,不要写死高度值 - 动画总时长可根据需求自由调整,节点切换的微小弹性动画能大幅提升交互质感
- 无需引入第三方动画库,原生CSS+JS即可实现全部效果,性能也更优
内容的提问来源于stack exchange,提问作者dev
相关产品推荐
相关产品推荐

