canvas虚线需在beginpath()后、stroke()前调用setlinedash()并配合linedashoffset,数组定义实/空长度,offset控制起始偏移,且须注意路径绑定、像素对齐及高dpi适配。

Canvas 绘制虚线靠的是 setLineDash() 和 lineDashOffset 两个核心机制,不是“设了就出效果”,关键在调用时机、路径绑定和像素对齐。
setLineDash:定义虚线节奏
它接收一个数组,按顺序交替解释为「实线长度」和「空白长度」。比如 [6, 4] 就是画 6 像素实线、跳 4 像素、再画 6 像素……无限循环。
- 数组长度为奇数(如
[3])时,Canvas 自动复制成偶数长度([3, 3]),无需手动补全 - 传空数组
[]或[0]会关闭虚线,恢复为实线;null或undefined会导致报错或静默失败,别依赖它“清空” - 想画点线?用
[0, 8]配合ctx.lineCap = 'round'和整数坐标,比[1, 8]更稳定不糊 - 数值支持小数(如
[2.5, 3.5]),但低于 0.5 可能被抗锯齿吞掉,建议最小用[2, 2]
lineDashOffset:控制起始位置
它是一个数值,表示整个虚线图案沿路径方向平移的距离。正值向终点偏,负值向起点偏——不是“移动某一段”,而是整体滑动图案。
- 常用于消除“断头感”:比如
ctx.lineDashOffset = 3让本该从空白开始的虚线,提前露出一段实线 - 动画中实现流动效果,只需每帧递增 offset 并取模循环,例如
offset = (offset + 0.3) % 10 - 偏移量是累积的,每次重绘前需主动赋值,Canvas 不会自动重置
- 旧版 Safari 对非整数偏移支持不稳定,生产环境建议取整处理
生效前提:路径与绘制必须匹配
虚线只对 stroke() 生效,且必须在 beginPath() 之后、stroke() 之前设置。漏掉任一环节,虚线就“看不见”。
-
strokeRect()、fillRect()、arc()等快捷方法内部隐式管理路径,不继承setLineDash设置;要加虚线边框,必须手动画路径:beginPath() → rect() → setLineDash() → stroke() - 高 DPI 屏幕(如 Retina)下,CSS 缩放会让虚线变密或模糊;需将 dash 数组每个值乘以
window.devicePixelRatio再传入 - 多条线用不同虚线样式?每条都得独立走一遍
beginPath() → setLineDash() → stroke()流程 - Firefox 有时会在
fill()后残留虚线状态,保险起见,每次stroke()前显式调用setLineDash
常见失效原因与应对
90% 的“虚线不显示”问题,根源不在参数写错,而在生命周期没理清。
- 没调
beginPath()就直接setLineDash()→ 补上beginPath() - 在
stroke()之后才调setLineDash()→ 把设置移到stroke()前 - 用
strokeRect()想套虚线 → 改用手动路径 +rect()+stroke() - 在非整数坐标(如
moveTo(10.5, 20.3))上画点线 → 改用Math.round(x)对齐像素











