通过 数学计算 + CSS mask 复合遮罩 实现的真正几何内凹效果:
背景是一张图片,用来证明中间的凹陷是透明的。
完整代码:
app.js
import FormPage from "./pages/formPage";
import "./App.css";
const App = () => {
return (
<div className="box">
<div className="block"></div>
</div>
);
};
export default App;
app.css
.box {
background: url(../src/pages/img/10.jpg) 100%;
height: 500px;
}
.block {
/* 增大圆角半径 */
--r: 6px;
/* 适当增加斜切长度 */
--s: 69px;
/* 微调角度使过渡更自然 */
--a: 44deg;
/* 更柔和的边缘过渡 */
--_m: 0/calc(2*var(--r)) var(--r) no-repeat radial-gradient(50% 100% at bottom, #000 calc(100% - 0.8px), transparent);
/* 自动计算的水平偏移 */
--_d: (var(--s) + var(--r)) * cos(var(--a));
width: 300px;
height: 100px;
background-color: antiquewhite;
border-radius: 150px;
mask:
calc(50% + var(--_d)) var(--_m), calc(50% - var(--_d)) var(--_m),
radial-gradient(var(--s) at 50% calc(-1*sin(var(--a))*var(--s)),
transparent 100%, #000 calc(100% + 0.8px)) 0 calc(var(--r)*(1 - sin(var(--a)))),
linear-gradient(90deg, #000 calc(50% - var(--_d)), transparent 0 calc(50% + var(--_d)), #000 0);
mask-repeat: no-repeat;
}
🧠 整体思路
这段代码的核心思想是:
使用多个 mask 图层组合,通过 radial-gradient 和 linear-gradient 的叠加,形成一个“中间凹进去、边缘过渡柔和”的视觉效果。
它利用了 CSS 中的变量(--r
, --s
, --a
)、三角函数和 mask
属性,实现了动态可配置的内凹圆角效果。
📏 变量解析(CSS Custom Properties)
--r: 6px; /* 凹陷区域的半径(控制凹陷大小) */
--s: 69px; /* 圆弧的半径(控制凹陷的位置) */
--a: 44deg; /* 角度(用于三角函数计算) */
这些变量可以方便地调整最终的视觉效果。
🧮 计算变量(关键逻辑)
--_m
:定义一个遮罩图层(更柔和的边缘过渡)
--_m: 0 / calc(2*var(--r)) var(--r) no-repeat
radial-gradient(50% 100% at bottom, #000 calc(100% - 0.8px), transparent);
- 创建一个宽度为
2 * --r
,高度为--r
的径向渐变。 - 渐变从底部开始,颜色从不透明到透明,形成一个边缘模糊的遮罩条带。
- 这个条带会在最终 mask 中作为“边缘柔化”层使用。
--_d
:水平偏移距离(基于三角函数自动计算)
--_d: (var(--s) + var(--r)) * cos(var(--a));
- 使用余弦函数计算出一个水平方向上的偏移值。
- 这个偏移值决定了凹陷区域在水平方向上的位置。
- 结合下面的 mask 设置,使凹陷区域对称分布在中心两侧。
🎭 Mask 图层详解(这是整个效果的关键)
mask:
calc(50% + var(--_d)) var(--_m),
calc(50% - var(--_d)) var(--_m),
radial-gradient(var(--s) at 50% calc(-1*sin(var(--a))*var(--s)),
transparent 100%, #000 calc(100% + 0.8px)) 0 calc(var(--r)*(1 - sin(var(--a)))),
linear-gradient(90deg, #000 calc(50% - var(--_d)), transparent 0 calc(50% + var(--_d)), #000 0);
我们来逐行拆解这四个 mask 图层:
🔹 第一层 & 第二层(边缘柔化层)
calc(50% + var(--_d)) var(--_m),
calc(50% - var(--_d)) var(--_m)
- 这两个图层使用的是之前定义好的
--_m
遮罩条带。 - 分别放置在中心左右各偏移
--_d
的位置。 - 作用是柔和边缘,避免生硬的裁剪边界。
🔸 第三层(核心凹陷层)
radial-gradient(var(--s) at 50% calc(-1*sin(var(--a))*var(--s)),
transparent 100%, #000 calc(100% + 0.8px))
0 calc(var(--r)*(1 - sin(var(--a))));
- 创建一个以中心为圆心、向上偏移一定距离的径向渐变。
- 半径为
--s
,位于垂直方向上偏移sin(a) * s
。 - 渐变从透明到黑色,超出部分变为不透明。
- 最后定位在
0 calc(...)
,即垂直方向向下偏移一点,让凹陷区域更贴合整体形状。
✅ 这一层是形成“内凹”视觉的核心图层。
🔷 第四层(背景遮罩层)
linear-gradient(90deg, #000 calc(50% - var(--_d)), transparent 0 calc(50% + var(--_d)), #000 0)
水平方向的线性渐变:
- 左侧和右侧为黑色(显示区域)
- 中间一段为透明(隐藏区域)
作用是遮住中间的凹陷区域,只保留两边的内容。
🧪 最终效果总结
图层 | 作用 |
---|---|
第一、二层 | 边缘柔化处理(避免锯齿感) |
第三层 | 核心凹陷区域(模拟“内凹”形状) |
第四层 | 背景遮罩(只显示两边,中间隐藏) |
结合起来就形成了一个中间凹陷、边缘柔和、对称分布的视觉效果,非常适合用在按钮、卡片等需要轻微凹陷质感的 UI 元素中。
🖼️ 示例效果预览(文字描述)
想象一个椭圆形的盒子(border-radius: 150px
),原本是完整的圆形。但在它的正中央,有一个向上弯曲的凹陷区域,就像轻轻按下按钮时那种感觉,边缘还有轻微的阴影过渡。
这种效果常见于 macOS 的菜单栏按钮、iOS 控件等现代 UI 设计中。
🛠️ 如何调整?
你可以通过修改以下变量来实时调整视觉效果:
变量 | 默认值 | 调整建议 | 影响 |
---|---|---|---|
--r |
6px |
增大 → 凹陷更大 | 凹陷区域大小 |
--s |
69px |
增大 → 凹陷更深 | 凹陷位置与深度 |
--a |
44deg |
增大 → 凹陷更靠上 | 凹陷角度与位置 |
background-color |
antiquewhite |
更浅/深色 | 整体对比度和质感 |