如何用JS与CSS实现不规则SVG描边手写动画,解决mask描边改白失效问题
问题描述
我参照相关教程完成了部分开发工作,目前mask层的动画可以正常运行。唯一的问题是我无法像教程中那样将.mask的stroke颜色修改为#fff,一旦修改,mask层就好像消失了一样,没有任何动画效果。
有人可以帮我理解为什么我无法实现字母"M"的线条手写绘制动画效果吗?
问题相关代码
JS代码
const masks = ["M"]; masks.forEach((mask, index, el) => { const id = `#Mask-${mask}`; let path = document.querySelector(id); const length = path.getTotalLength(); path.style.strokeDasharray = length; path.style.strokeDashoffset = length; });
CSS代码
.Character { cursor: pointer; position: absolute; fill: #000000; left: 0; top: 0; } #Char-M { mask: url(#Mask-M); } .mask { fill: none; stroke: #333; stroke-miterlimit: 10; stroke-width: 171px; stroke-linecap: round; stroke-linejoin: bevel; stroke-dasharray: 1000; stroke-dashoffset: 1000; } @keyframes strokeOffset { to { stroke-dashoffset: 0; } } #Mask-M { animation: strokeOffset 3s linear infinite; }
HTML代码
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 559.4 535.94"> > <g id="Mask-Layer"> <g id="Mask"> <path id="Mask-M" class="mask" d="M90.89,534.25l-4-412c-.54-16.52-4.5-27.17,4-13l165.23,232.5A28.56,28.56,0,0,0,303,341.3L455.79,95.19c9.49-15.28,18.5-11.92,18.1,6.06l-6,433.5"/> </g> </g> <g id="Character-Layer"> <g id="Character"> <path id="Char-M" data-name="M" d="M241.39,405.9H216L35.81,102.69V526.41H13.18V64.48H38.64Zm-183-236.54L81,207.58V526.41H58.45ZM292.59,405.9H266.87L64.39,64.48H90.17ZM103.72,245.75l22.67,38V526.41H103.72Zm420-143.1L343.58,405.9H317.8L115.66,64.48h25.47L331,384.75,520.56,64.53h25.83V526.41H523.76ZM149,322.22l22.63,37.94V526.41H149Zm151.52-17.57-13.2-21.2,130.77-219h25.78Zm26.09,43.79-12.89-20.92,155.93-263H495.1Zm61.3,9.48L410.54,320V526.41H387.9Zm45.27-77L455.81,243V526.41H433.17ZM478.44,205l22.63-38.21V526.41H478.44Z"/> </g> </g> </svg>
问题解答
异常原因
- SVG mask语法不规范:
mask属性只能引用<mask>标签元素,当前直接将字符的mask属性指向了普通path节点,属于不规范写法,不同浏览器的兼容逻辑不同,所以修改stroke颜色会出现不可预期的渲染异常。 - 遮罩计算规则冲突:即使部分浏览器兼容直接用path做遮罩,默认也会按亮度计算遮罩透明度:遮罩内容越白,被遮罩的元素对应区域越可见,把stroke改成纯白色后,遮罩区域完全显示,就会产生“mask消失、动画失效”的错觉。
- 冗余配置冲突:JS已经动态计算了路径总长度并设置了内联的描边dash配置,CSS中又给
.mask设置了固定的stroke-dasharray、stroke-dashoffset,容易引发样式优先级冲突。 - SVG代码语法错误:SVG标签后多了一个多余的
>符号,会导致部分浏览器渲染异常。
修复方案
- 调整SVG结构,将mask路径放到规范的
<mask>标签中,并添加mask-type="alpha"属性,让遮罩直接按描边的透明度计算,完全不受stroke颜色影响。 - 删除CSS中
.mask下冗余的描边dash配置,统一使用JS动态计算的路径长度,适配不同字符的路径尺寸。 - 删掉SVG代码中多余的
>符号。
修复后完整代码
CSS
.Character { cursor: pointer; position: absolute; fill: #000000; left: 0; top: 0; } #Char-M { mask: url(#Mask-M); -webkit-mask: url(#Mask-M); /* 兼容webkit内核浏览器 */ } .mask { fill: none; stroke: #fff; /* 现在可以随意修改stroke颜色,不会影响遮罩效果 */ stroke-miterlimit: 10; stroke-width: 171px; stroke-linecap: round; stroke-linejoin: bevel; } @keyframes strokeOffset { to { stroke-dashoffset: 0; } } #Mask-M path { animation: strokeOffset 3s linear infinite; }
HTML
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 559.4 535.94"> <defs> <mask id="Mask-M" mask-type="alpha"> <path class="mask" d="M90.89,534.25l-4-412c-.54-16.52-4.5-27.17,4-13l165.23,232.5A28.56,28.56,0,0,0,303,341.3L455.79,95.19c9.49-15.28,18.5-11.92,18.1,6.06l-6,433.5"/> </mask> </defs> <g id="Character-Layer"> <g id="Character"> <path id="Char-M" data-name="M" d="M241.39,405.9H216L35.81,102.69V526.41H13.18V64.48H38.64Zm-183-236.54L81,207.58V526.41H58.45ZM292.59,405.9H266.87L64.39,64.48H90.17ZM103.72,245.75l22.67,38V526.41H103.72Zm420-143.1L343.58,405.9H317.8L115.66,64.48h25.47L331,384.75,520.56,64.53h25.83V526.41H523.76ZM149,322.22l22.63,37.94V526.41H149Zm151.52-17.57-13.2-21.2,130.77-219h25.78Zm26.09,43.79-12.89-20.92,155.93-263H495.1Zm61.3,9.48L410.54,320V526.41H387.9Zm45.27-77L455.81,243V526.41H433.17ZM478.44,205l22.63-38.21V526.41H478.44Z"/> </g> </g> </svg>
JS
const masks = ["M"]; masks.forEach((mask) => { const maskEl = document.querySelector(`#Mask-${mask} .mask`); const length = maskEl.getTotalLength(); maskEl.style.strokeDasharray = length; maskEl.style.strokeDashoffset = length; });
内容的提问来源于stack exchange,提问作者marcos.garcia
相关产品推荐
相关产品推荐

