stroke-dasharray 是 svg 路径的虚线配置属性,用两个数字控制“画多长、空多长”;它本身不动画,需配合 stroke-dashoffset 位移及 css transition 或 js 动画驱动才实现动态效果。

stroke-dasharray 是什么,为什么它能动起来
它不是动画 API,而是 SVG 路径的“虚线绘制开关”——用两个数字控制“画多长、空多长”。真正让它动起来的,是配合 stroke-dashoffset 做位移,再用 CSS transition 或 @keyframes 驱动偏移量变化。
常见错误现象:stroke-dasharray 设了但没动,大概率是没算对路径总长度,或者忘了设 stroke-dashoffset 初始值;更隐蔽的是:用 getTotalLength() 取长度时,路径还没渲染(比如 DOM 没挂载完或 display: none),返回 0。
- 必须在路径已渲染且可见状态下调用
getTotalLength(),推荐放在DOMContentLoaded后或用requestAnimationFrame延迟一次 - 响应式场景下,窗口缩放可能改变路径尺寸,需监听
resize并重算长度(或用viewBox+ 百分比路径避免重算) -
stroke-dasharray="10,5"表示“画 10px、空 5px”,而stroke-dasharray="100"等价于"100,100",不是“只画 100px”
怎么让描边从头到尾“画出来”(最常用场景)
核心逻辑:把 stroke-dasharray 设为路径全长,stroke-dashoffset 从全长变为 0,视觉上就是“从无到有”画完。
使用场景:加载指示器、图标入场、进度可视化。
立即学习“前端免费学习笔记(深入)”;
svg path {
stroke-dasharray: 100;
stroke-dashoffset: 100;
transition: stroke-dashoffset 0.6s ease-out;
}
svg path.drawn {
stroke-dashoffset: 0;
}
- 别硬编码
100——实际要用 JS 动态写入真实长度:path.style.strokeDasharray = len;path.style.strokeDashoffset = len - IE 不支持
stroke-dashoffset的 transition,如需兼容,得用SMIL(已废弃)或 JSrequestAnimationFrame手动更新 - 如果路径含
fill,注意描边动画期间fill会立刻显示,可能造成“先填色后画线”的错觉,可加fill-opacity: 0配合动画同步显隐
stroke-dashoffset 负值有什么用
负值 ≠ 报错,它是合法偏移,作用是让虚线图案“往回挪”,常用于循环滚动效果或反向动画。
性能影响小,但容易被当成 bug:比如设了 stroke-dashoffset: -20,结果发现线条从中间开始“漏出一段”,其实是虚线图案整体左移了 20px,第一段“画”的部分被移出了起点。
- 做无限滚动时,可用
@keyframes让stroke-dashoffset从 0 变到-len,再跳回 0,视觉无缝(注意用animation-timing-function: linear) - 和
stroke-dasharray组合时,负 offset 会暴露原本被“空”遮住的部分,适合做呼吸式闪烁或节奏型高亮 - 某些 SVG 编辑器导出的路径带
transform,会影响getTotalLength()结果,此时负 offset 表现可能异常,优先检查路径是否被缩放/旋转
为什么用 CSS 动画不如 requestAnimationFrame 精确
CSS transition 和 @keyframes 依赖浏览器样式计算与合成层刷新,对描边这种需要像素级同步的动画,容易出现卡顿、跳帧或起始/结束点不稳。
尤其当页面有其他 heavy 动画、或 SVG 在 will-change: transform 容器里时,CSS 动画可能被降级到低帧率。
- 关键帧动画中,
stroke-dashoffset的插值是线性的,但人眼对描边“启动/停止”敏感,建议用cubic-bezier(.33,.66,.66,1)模拟手绘感 - JS 方案更可控:用
requestAnimationFrame手动更新strokeDashoffset,可结合时间戳做匀速/变速,也能随时暂停、反转、跳转 - 不要在每帧都调用
getTotalLength()——它触发 layout,应缓存长度值
<path d="M0,0 L100,100"></path> 和 <path d="M0,0L100,100"></path> 在某些解析器下长度不同;带弧线、贝塞尔曲线的路径,getTotalLength() 返回值未必是整数——这些细节,调试时得盯着 DevTools 里实时输出的数值看。










