<p>clip-path 实现自适应打孔缺角需避开 Safari 旧版兼容性坑:iOS 15.4 前优先用 polygon() + vw/vh 或 inset() + border-radius;圆角打孔可叠加 overflow: hidden + border-radius;高保真圆形打孔推荐 mask-image 配合 radial-gradient 并补全 -webkit- 前缀;兜底方案用伪元素 rotate(45deg) 斜切并设 overflow: hidden;响应式建议用 CSS 变量驱动 clip-path,配合 @supports 检测确保兼容。</p>

用 clip-path 实现自适应打孔缺角,但得避开 Safari 旧版坑
纯 CSS 实现移动端卡券的打孔/缺角效果,clip-path 是目前最可靠的选择——不用图片、不依赖伪元素堆叠、能随容器缩放自动适配。但注意:iOS 15.4 之前 Safari 对 clip-path 的 path() 和百分比坐标支持不稳定,必须降级到 polygon() + 视口单位(vw/vh)或使用 inset() 配合 border-radius 组合。
常见错误是直接写 clip-path: path("M0,0 L100,0 L100,100 Z"),结果在 iOS 上完全不生效或错位。真机调试时务必在 iPhone 实机上验证,模拟器有时会误报兼容性。
- 优先用
clip-path: polygon(0% 0%, 100% 0%, 100% 85%, 85% 100%, 0% 100%)模拟右下缺角,5 个点确保平滑过渡 - 缺角尺寸想随屏幕变化?把
85%换成calc(100% - 24px),但注意 Safari 对 calc 在 polygon 中的支持从 iOS 16.4 才完善,稳妥起见用90vw这类视口单位 - 若需圆角缺角(比如打孔感),别只靠
clip-path,叠加border-radius: 50%到子元素再用overflow: hidden遮罩
用 mask-image 做高保真打孔,但得处理安卓 WebView 兼容性
如果缺角需要精确圆形打孔(如模拟实体卡券的金属孔),mask-image 配合 radial-gradient 更可控,且能保持边缘抗锯齿。但它在 Android 系统 WebView(尤其旧版 UC、QQ 浏览器内核)中默认关闭,必须显式开启 -webkit-mask-image 并补全前缀。
典型错误是只写 mask-image: radial-gradient(circle at 90% 90%, transparent 12px, black 12px),结果在部分安卓机型上整个元素变黑或消失。
立即学习“前端免费学习笔记(深入)”;
- 必须同时声明:
-webkit-mask-image和mask-image,值完全一致 - 透明区域用
transparent,遮罩主体用black(不是white),否则逻辑反了 - 打孔位置用
circle at 90% 90%而非像素值,保证横竖屏切换时仍锚定右下角 - 测试时打开 Chrome DevTools → Rendering → “Emulate CSS media features” → 强制启用
mask特性,提前暴露兼容问题
用伪元素 + transform: rotate() 模拟斜切缺角,适合老设备兜底
当目标用户包含大量 iOS 14 或安卓 8 以下设备时,clip-path 和 mask-image 都可能失效,这时用 ::before 伪元素盖一个白色三角形,再用 rotate(45deg) 斜切,是最兼容的 fallback 方案。
关键不是“怎么画三角”,而是“怎么对齐不露边”。很多人伪元素一加就发现缺角边缘发虚或偏移几个像素,本质是没重置 transform-origin 和忽略父容器 overflow。
- 父容器必须设
overflow: hidden,否则旋转后伪元素溢出 - 伪元素用
position: absolute; top: auto; right: 0; bottom: 0;锚定右下,再transform-origin: bottom right - 尺寸用
width: 40px; height: 40px;固定,配合background: white,避免用border拼三角(不同设备 border 渲染精度不一) - 旋转角度严格用
rotate(45deg),别用skew,后者在低分辨率屏上容易出现亚像素模糊
响应式断点里别硬写 clip-path 值,用 CSS 自定义属性动态注入
同一个缺角,在 iPhone SE 屏上可能是 16px,在 iPad Pro 上得变成 32px,如果每个媒体查询里都复制粘贴 polygon() 值,维护成本爆炸。直接用 CSS 变量驱动更稳。
容易被忽略的是:变量不能直接塞进 polygon() 里,必须用 calc() 包一层,否则解析失败;而且变量名别用 --hole-size 这种带连字符的,Safari 旧版会静默忽略。
- 定义:
:root { --hole: 24; }(只存数字,不带单位) - 使用:
clip-path: polygon(0% 0%, 100% 0%, 100% calc(100% - var(--hole) * 1px), calc(100% - var(--hole) * 1px) 100%, 0% 100%) - 媒体查询中只需改
--hole值:@media (min-width: 768px) { :root { --hole: 36; } } - JavaScript 动态调整时,用
document.documentElement.style.setProperty('--hole', '28'),别用style.cssText全量覆盖
真正难的不是写出一个缺角,而是让这个缺角在微信内置浏览器、钉钉 H5 容器、PWA 离线环境里都保持位置精准、边缘锐利、缩放不糊。多一层 @supports (clip-path: polygon()) 检测,就少一个线上白屏事故。


















