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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 15:12:57