如何使用SVG路径遮罩DIV以实现前端漏斗图
如何使用SVG路径遮罩DIV以实现前端漏斗图
嘿,我最近在折腾前端漏斗图,想搞个简单的结构实现,一开始打算把各个漏斗段用flex行来布局,后来发现用SVG路径遮罩的方式更灵活,效果也更自然,下面就来分享下具体的实现思路和代码:
一、HTML基础结构
先搭好漏斗的容器框架,每个漏斗包含标题和分段,分段用data-from和data-to定义上下宽度的比例(数值范围0-1),方便后续动态计算形状:
<div class="funnel"> <h3>用户转化漏斗</h3> <div class="funnel-segments"> <div class="funnel-segment" data-from="1" data-to="0.8" style="background: #4CAF50;"> <div class="segment-label">访问网站<br>10000人</div> </div> <div class="funnel-segment" data-from="0.8" data-to="0.5" style="background: #2196F3;"> <div class="segment-label">注册账号<br>8000人</div> </div> <div class="funnel-segment" data-from="0.5" data-to="0.3" style="background: #FF9800;"> <div class="segment-label">加入购物车<br>5000人</div> </div> <div class="funnel-segment" data-from="0.3" data-to="0" style="background: #F44336;"> <div class="segment-label">完成购买<br>3000人</div> </div> </div> </div>
二、CSS样式配置
给漏斗和分段设置基础样式,重点是让分段能居中显示内容,同时预留好遮罩的应用位置:
.funnel { width: 400px; margin: 20px auto; font-family: Arial, sans-serif; } .funnel h3 { text-align: center; margin-bottom: 15px; } .funnel-segments { display: flex; flex-direction: column; gap: 2px; /* 分段之间的细微间隔,增强层次感 */ } .funnel-segment { position: relative; height: 80px; display: flex; align-items: center; justify-content: center; color: white; text-align: center; /* 遮罩属性会通过JS动态添加 */ } .segment-label { z-index: 1; position: relative; /* 确保文字不会被遮罩影响 */ } /* 隐藏SVG容器,只用作遮罩载体 */ .mask-svg { position: absolute; width: 0; height: 0; }
三、JS动态生成SVG遮罩
核心逻辑是根据每个分段的data-from和data-to,计算出平滑的SVG贝塞尔曲线路径,然后生成遮罩应用到分段上:
document.addEventListener('DOMContentLoaded', function() { let funnels = document.getElementsByClassName('funnel'); // 创建全局SVG容器,用来存放所有遮罩元素 const svgContainer = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svgContainer.classList.add('mask-svg'); document.body.appendChild(svgContainer); for (let i = 0; i < funnels.length; i++) { let segments = funnels[i].querySelector('.funnel-segments').children; for (let j = 0; j < segments.length; j++) { const segment = segments[j]; const from = parseFloat(segment.getAttribute('data-from')); const to = parseFloat(segment.getAttribute('data-to')); const difference = (from - to) / 2; // 生成平滑的漏斗形状路径,用贝塞尔曲线实现自然过渡 const d = `M 0 ${50 - from * 50} Q 25 ${50 - from * 50} 50 ${50 - ((to + difference) * 50)} T 100 ${50 - to * 50} V ${50 + to * 50} Q 75 ${50 + to * 50} 50 ${50 + ((to + difference) * 50)} T 0 ${50 + from * 50} Z`; // 生成唯一的遮罩ID,避免冲突 const maskId = `funnel-mask-${i}-${j}`; // 创建SVG遮罩元素 const mask = document.createElementNS('http://www.w3.org/2000/svg', 'mask'); mask.setAttribute('id', maskId); const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('d', d); path.setAttribute('fill', 'white'); mask.appendChild(path); svgContainer.appendChild(mask); // 给当前分段应用遮罩 segment.style.webkitMask = `url(#${maskId})`; segment.style.mask = `url(#${maskId})`; } } });
四、实现思路说明
- 用
data-from和data-to定义分段的上下宽度比例,通过JS计算路径点,让漏斗形状可以灵活调整 - 借助SVG遮罩特性,让DIV只显示路径覆盖的区域,实现漏斗的渐变梯形/三角形效果
- 贝塞尔曲线的使用让漏斗边缘更平滑,比纯CSS做的梯形过渡更自然
这样一套实现下来,既能快速搭建出美观的漏斗图,还能通过修改属性值轻松调整形状和配色,适配不同的场景需求~
备注:内容来源于stack exchange,提问作者Lucas FAURE
相关产品推荐
相关产品推荐

