clip-path: path() 是移动端底部菜单凹凸造型最可靠方案,ios safari 16.4+ 和 android chrome 100+ 稳定支持;mask-image 在 ios 存在渲染抖动、缩放失真、点击区域错位等硬伤,不建议生产使用。

直接说结论:在移动端 Web 场景下,mask-image 和 clip-path 都能实现底部菜单的凹凸造型,但实际可用性差异极大——clip-path(尤其是 path() 语法)在 iOS Safari 16.4+ 和 Android Chrome 100+ 中已稳定支持,而 mask-image 的 SVG mask 或 url(#id) 方式在 iOS 上仍存在渲染抖动、缩放失真、无法响应点击区域等硬伤,不建议生产环境使用。
clip-path: path() 是目前最靠谱的方案
真正能落地的凹陷/凸起效果,核心是用 SVG 贝塞尔路径描述底部轮廓,再通过 clip-path: path("M...") 截取导航栏容器。关键不是“能不能画”,而是“能不能对齐、能不能响应、能不能适配不同屏幕”。
- 路径坐标必须基于容器自身宽高归一化(比如用
100vw和100vh计算,或 JS 动态注入像素值),不能写死 px 值,否则横竖屏切换就错位 - 中间凹陷部分的控制点要预留足够空间给 FAB 按钮,常见做法是让凹口宽度 = 按钮直径 + 8px 间隙,深度 ≈ 按钮半径 × 0.7
- Android WebView 对
path()支持早于 iOS,但 iOS 16.4 是分水岭——低于此版本会回退为矩形裁剪,需加降级样式:clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%) - 不要把
clip-path直接写在BottomNavigation根元素上;应包裹一层<div class="tabbar-clipper">,否则子元素(如图标、文字)的点击热区可能被裁掉 <h3>mask-image 在 iOS 上的三个典型翻车现场</h3> <p>即便你用的是 inline SVG + <code>mask-image: url(#myMask),iOS Safari 仍大概率出问题:- 页面滚动时 mask 区域突然偏移,尤其配合
position: fixed的 tabbar —— 这是 WebKit 已知 bug,无完美绕过,只能禁用滚动时的 mask 更新 - 高清屏(@2x/@3x)下 mask 边缘出现 1px 锯齿或半透明晕染,因为 mask 图像未按 devicePixelRatio 缩放
- 凹陷区域内的按钮点击无效:mask 只影响视觉呈现,不改变 hit-testing 区域,iOS 会把整个原始矩形框都当作可点击区,导致点到“看不见的凹口边缘”就触发跳转
如何让凹陷区域真正“可交互”
光有视觉凹陷不够,用户得能准确点中中间按钮、且两侧 tab 不误触。这需要组合手段:
- 凹口正下方必须有一个独立的
<button></button>或<view></view>元素,z-index > tabbar,且明确设置pointer-events: auto(默认可能被父层继承为none) - 两侧 tab item 的
padding-left/right要手动加大,把原本凹口位置“空出来”,避免手指滑动时误点 - 用
getBoundingClientRect()在resize和orientationchange后重新计算凹口坐标并重设clip-path,否则横屏后凹口位置就歪了 - 别依赖 CSS 动画驱动 clip-path 变化——WebKit 对 path 动画支持极差,改用
transform: translateY()模拟凹陷深度变化更稳
真正难的从来不是“怎么画出那个形状”,而是让这个形状在各种机型、系统版本、横竖屏、缩放设置下,既看起来对,又点得准,还不会闪、不卡、不误触。这些细节不写死在代码里,只靠“调一下 CSS”是搞不定的。
- 页面滚动时 mask 区域突然偏移,尤其配合











