如何创建带边框的Squircle?求兼容多浏览器的替代方案
如何创建带边框、阴影或内发光的Squircle?
我目前尝试过两种方案,但都存在缺陷:
- Houdini的CSS paintWorklet:浏览器支持率仅71.35%(2023年),Safari(iOS/macOS)和Firefox因安全漏洞暂不支持。
- SVG
<clipPath>:添加边框需要重绘路径,缩放等变换操作复杂,CSS属性需转成路径数据,示例代码如下:
<svg xmlns="http://www.w3.org/2000/svg" width="220" height="220" viewBox="-10 -10 220 220"> <defs> <clipPath id="squircle-clip"> <path d="M20,0 L180,0 Q200,0 200,20 L200,180 Q200,200 180,200 L20,200 Q0,200 0,180 L0,20 Q0,0 20,0" style="vector-effect: non-scaling-stroke;" /> </clipPath> </defs> <rect x="0" y="0" width="200" height="200" fill="#222" clip-path="url(#squircle-clip)" /> <path d="M20,0 L180,0 Q200,0 200,20 L200,180 Q200,200 180,200 L20,200 Q0,200 0,180 L0,20 Q0,0 20,0" fill="none" stroke="#484848" stroke-width="2" style="vector-effect: non-scaling-stroke;" /> </svg>
寻求其他兼容性好、操作简单的实现方法。
可行替代方案
1. CSS mask + 伪元素(兼容性佳,操作简单)
利用CSS mask 属性裁剪出Squircle形状,通过伪元素实现边框,同时原生box-shadow支持阴影和内发光,无需处理复杂路径变换。
示例代码:
.squircle { width: 200px; height: 200px; position: relative; background: #222; /* 内嵌SVG作为遮罩,定义Squircle路径 */ -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><path d="M20,0 L180,0 Q200,0 200,20 L200,180 Q200,200 180,200 L20,200 Q0,200 0,180 L0,20 Q0,0 20,0"/></svg>'); mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><path d="M20,0 L180,0 Q200,0 200,20 L200,180 Q200,200 180,200 L20,200 Q0,200 0,180 L0,20 Q0,0 20,0"/></svg>'); } /* 边框实现:伪元素放大并继承遮罩,作为底层边框 */ .squircle::before { content: ''; position: absolute; inset: -2px; /* 边框宽度 */ background: #484848; -webkit-mask: inherit; mask: inherit; z-index: -1; } /* 外部阴影:直接添加,会被mask自动裁剪 */ .squircle.shadow { box-shadow: 0 8px 16px rgba(0,0,0,0.3); } /* 内发光:使用inset阴影 */ .squircle.inner-glow { box-shadow: inset 0 0 12px rgba(255,255,255,0.4); }
<div class="squircle shadow inner-glow"></div>
核心优势:
- 浏览器支持率高(
mask除IE外全平台覆盖) - 边框、阴影、内发光用标准CSS属性控制,缩放时自动适配,无需修改路径
- 伪元素继承遮罩,无需重复定义Squircle路径
2. 优化版SVG路径绘制(避免clipPath冗余)
直接用SVG的<path>绘制Squircle主体和边框,通过<use>复用路径减少冗余,vector-effect: non-scaling-stroke保证边框宽度不随缩放变化。
示例代码:
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"> <defs> <!-- 定义复用的Squircle路径 --> <path id="squircle-path" d="M20,0 L180,0 Q200,0 200,20 L200,180 Q200,200 180,200 L20,200 Q0,200 0,180 L0,20 Q0,0 20,0"/> <!-- 阴影滤镜 --> <filter id="squircle-shadow" x="-20%" y="-20%" width="140%" height="140%"> <feDropShadow dx="4" dy="4" stdDeviation="6" flood-color="rgba(0,0,0,0.3)"/> </filter> <!-- 内发光滤镜 --> <filter id="squircle-inner-glow" x="-20%" y="-20%" width="140%" height="140%"> <feFlood flood-color="rgba(255,255,255,0.4)"/> <feComposite in2="SourceAlpha" operator="in"/> <feGaussianBlur stdDeviation="6"/> <feComposite in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1"/> <feMerge> <feMergeNode/> <feMergeNode in="SourceGraphic"/> </feMerge> </filter> </defs> <!-- 阴影层 --> <use href="#squircle-path" filter="url(#squircle-shadow)" fill="#222"/> <!-- 主体层 --> <use href="#squircle-path" fill="#222"/> <!-- 边框层 --> <use href="#squircle-path" fill="none" stroke="#484848" stroke-width="2" vector-effect="non-scaling-stroke"/> <!-- 内发光层(取消注释启用) --> <!-- <use href="#squircle-path" filter="url(#squircle-inner-glow)" fill="#222"/> --> </svg>
优化点:
- 移除
clipPath,直接绘制路径,减少DOM冗余 - 用
<use>标签复用路径,避免重复书写d属性 - 缩放时仅需修改SVG的
width/height,路径自动适配,边框宽度保持不变
3. CSS border-radius 近似模拟(极简方案)
如果对Squircle的曲线精度要求不高,可以用高阶border-radius值近似模拟,配合border和box-shadow快速实现效果。
示例代码:
.squircle-approx { width: 200px; height: 200px; background: #222; /* 调整百分比优化曲线弧度,接近Squircle效果 */ border-radius: 40% 40% 40% 40% / 40%; border: 2px solid #484848; box-shadow: 0 8px 16px rgba(0,0,0,0.3); box-shadow: inset 0 0 12px rgba(255,255,255,0.4); }
优势:纯CSS实现,无需SVG或Houdini,兼容性拉满;缺点是曲线精度不如标准Squircle。
内容的提问来源于stack exchange,提问作者Greg Wolff
相关产品推荐
相关产品推荐

