You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何增大stroke-width后SVG进度条路径显示异常?

SVG仪表盘进度条宽幅时被矩形截断的问题分析与解决

问题场景

我用SVG制作了一个带栅栏遮罩的仪表盘进度条,核心代码如下:

<svg
  class="progress-dashboard"
  viewBox="0 0 80 80"
  stroke-width="10"
  stroke-dasharray="127.17, 1000"
  stroke-dashoffset="0"
>
  <style>
/* <![CDATA[ */
.progress-transition {
  transition: stroke-dashoffset 0.3s ease 0s, stroke-dasharray 0.3s ease 0s, stroke 0.3s ease 0s, stroke-width 0.06s ease 0.3s, opacity 0.3s ease 0s;
}
/* ]]> */
  </style>

  <defs>
<filter id="bloom">
  <feGaussianBlur in="SourceGraphic" stdDeviation="0.5" />
  <feMerge>
      <feMergeNode />
      <feMergeNode in="SourceGraphic" />
  </feMerge>
</filter>

<linearGradient id="gradient" x1="50%" y1="0%" x2="0%" y2="50%">
  <stop offset="0%" stop-color="#008cfa"></stop>
  <stop offset="100%" stop-color="#0ffafa"></stop>
</linearGradient>

<mask id="fence">
  <path
    class="progress-dashboard-mask progress-transition"
    d="M 40,40 m 0,-27
      a 27,27 0 1 1 0,54
      a 27,27 0 1 1 0,-54"
    stroke="white"
    stroke-linecap="butt"
    stroke-width="inherit"
    stroke-dasharray="0.73px, 1.3px"
    stroke-dashoffset="0px"
    opacity="1"
    fill-opacity="0"
    filter="url(#bloom)"
  >
  </path>
</mask>
  </defs>

  <g transform-origin="50%" transform="rotate(225)">
<path
  class="progress-dashboard-background progress-transition"
  d="M 40,40 m 0,-27
      a 27,27 0 1 1 0,54
      a 27,27 0 1 1 0,-54"
  stroke="gray"
  stroke-linecap="butt"
  stroke-width="inherit"
  stroke-dasharray="inherit"
  stroke-dashoffset="0px"
  opacity="1"
  fill-opacity="0"
  mask="url(#fence)"
>
</path>

<path
  class="progress-dashboard-frontground progress-transition"
  d="M 40,40 m 0,-27
      a 27,27 0 1 1 0,54
      a 27,27 0 1 1 0,-54"
  stroke="url(#gradient)"
  stroke-linecap="butt"
  stroke-width="inherit"
  stroke-dasharray="inherit"
  stroke-dashoffset="inherit"
  opacity="1"
  fill-opacity="0"
  filter="url(#bloom)"
  mask="url(#fence)"
>
</path>
  </g>
</svg>

进度条通过fence路径作为遮罩实现栅栏效果,当stroke-width≤10时显示正常,但增大到15、30等值后,路径会被矩形截断,且宽度越大截断越明显。

原因分析

问题出在遮罩的默认边界计算上:

  • SVG的<mask>元素默认以所在SVG的视口(viewBox="0 0 80 80")作为遮罩有效区域,超出视口的内容会被裁剪。
  • 当stroke-width增大时,遮罩路径的描边会向外扩展,超出80×80的视口范围,超出部分被截断后,导致应用遮罩的进度条也出现矩形截断效果。
  • 遮罩路径上的filter="url(#bloom)"高斯模糊效果,会进一步扩大元素渲染范围,加剧了超出视口的情况。

解决方案

方法1:扩大SVG视口并调整路径参数

给描边和模糊效果留出足够空间,同时保证进度条视觉中心不变:

  • 将viewBox改为0 0 140 140(根据最大stroke-width调整,比如30的话,左右各加30,80+60=140)
  • 路径圆心调整为70,70,半径从27改为57,让进度条保持在视口中心

修改后的核心代码片段:

<svg
  class="progress-dashboard"
  viewBox="0 0 140 140"
  stroke-width="30"
  stroke-dasharray="358.14, 1000"
  stroke-dashoffset="0"
>
<!-- ... 其他代码 ... -->
<path
    class="progress-dashboard-mask progress-transition"
    d="M 70,70 m 0,-57
      a 57,57 0 1 1 0,114
      a 57,57 0 1 1 0,-114"
    <!-- ... 其他属性不变 ... -->
>
</path>
<!-- 背景和前景路径的d属性同步修改为M 70,70 m 0,-57 ... -->
</svg>

方法2:给遮罩添加相对单位属性

通过maskContentUnits="objectBoundingBox"让遮罩基于被遮罩元素的边界盒计算,摆脱视口限制:

  • 在<mask>标签中添加maskContentUnits="objectBoundingBox"
  • 将遮罩路径的坐标转换为0-1的相对值,比如圆心改为0.5,0.5,半径改为0.3375(27/80=0.3375),描边虚线也同步转为相对值

修改后的遮罩部分代码:

<mask id="fence" maskContentUnits="objectBoundingBox">
  <path
    class="progress-dashboard-mask progress-transition"
    d="M 0.5,0.5 m 0,-0.3375
      a 0.3375,0.3375 0 1 1 0,0.675
      a 0.3375,0.3375 0 1 1 0,-0.675"
    stroke="white"
    stroke-linecap="butt"
    stroke-width="inherit"
    stroke-dasharray="0.009125, 0.01625" <!-- 原0.73/80=0.009125,1.3/80=0.01625 -->
    stroke-dashoffset="0px"
    opacity="1"
    fill-opacity="0"
    filter="url(#bloom)"
  >
  </path>
</mask>

这种方法无需修改SVG视口,更灵活适配不同的stroke-width。


内容的提问来源于stack exchange,提问作者XUX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 17:07:28