核心Css:clip-path
核心js:计算四个象限的内角路径
设计师搞了一个酷炫的渐变圆角边框。然而,web端的css,边框可以渐变,也可以圆角,却不能渐变+圆角。网络上找了蛮多解决方案的。大体有以下几类:
总之,找了一圈,没找到符合心意的。自己尝试设想了方案:
最后决定使用clip-path先尝试下,毕竟这玩意儿支持calc、%、+、-、*、/。
使用clip-path裁剪,我们只要把内角的圆滑度裁剪出来就好了,外层的圆滑使用自带的border-raduis就行。那么,我们就先不考虑内角是否圆滑,把整体的大致轮廓先裁剪出来。效果和裁剪逻辑如下:
clip-path:polygon(
0 50%,
0 100%,
100% 100%,
100% 0,
0 0,
0 50%,
borderWidth 50%,
borderRadius borderWidth,
calc(100% - borderRadius) borderWidth,
calc(100% - borderWidth) borderRadius,
calc(100% - borderWidth) calc(100% - borderRadius),
calc(100% - borderRadius) calc(100% - borderWidth),
borderRadius calc(100% - borderWidth),
borderWidth calc(100% - borderRadius),
borderWidth 50%,
0 50%
);
可能这么说不太好理解,我把裁剪路线图给描出来,或许就简单很多了。
其中,A、F、Q三个点重合,G、P三个重合,裁剪图形看着像反过来的C。只不过渲染效果不是开口的,而是闭口的。
之后,我们需要把HI、JK、LM、NO这四段路径整成圆滑的弧形。我们先来看一个图:
R:border-radius,外层圆的半径
W:border-width,指定的边框宽度
r:内层圆的半径
以第一象限为例
可以计算出x和y的相对偏移位置,以此,我们可以类推出其余三个象限。(ps:夹角我们以射线与x轴最近的那个为准)
第二象限的内圆路径(左上)
x = R - (R - w) * cos(radian)
y = R - (R - w) * sin(radian)
第一象限的内圆路径(右上)
x = 100% - R + (R - w) * cos(PI / 2 - radian)
y = R - (R - w)*sin(PI / 2 - radian)
第四象限的内圆路径(右下)
x = 100% - R + (R - w) * cos(radian)
y = 100% - R + (R - w) * sin(radian)
第三象限的内圆路径(左下)
x = R - (R - w) * cos(PI / 2 - radian)
y = 100% - R + (R - w) * sin(PI / 2 - radian)
const quadrantFunc = {
1: {
getX: (radian, lr, sr) => {
const swap = sr * Math.cos(Math.PI / 2 - radian) - lr;
const x = `calc(100% + ${swap}px)`;
return x;
},
getY: (radian, lr, sr) => {
const y = lr - sr * Math.sin(Math.PI / 2 - radian);
return `${y}px`;
}
},
2: {
getX: (radian, lr, sr) => {
const x = lr - sr * Math.cos(radian);
return `${x}px`;
},
getY: (radian, lr, sr) => {
const y = lr - sr * Math.sin(radian);
return `${y}px`;
}
},
3: {
getX: (radian, lr, sr) => {
const x = lr - sr * Math.cos(Math.PI / 2 - radian);
return `${x}px`;
},
getY: (radian, lr, sr) => {
const swap = sr * Math.sin(Math.PI / 2 - radian) - lr;
const y = `calc(100% + ${swap}px)`;
return y;
}
},
4: {
getX: (radian, lr, sr) => {
const swap = sr * Math.cos(radian) - lr;
const x = `calc(100% + ${swap}px)`;
return x;
},
getY: (radian, lr, sr) => {
const swap = sr * Math.sin(radian) - lr;
const y = `calc(100% + ${swap}px)`;
return y;
}
},
};
至此,我们的裁剪路径就变为
clip-path: polygon(
0 50%,
0 100%,
100% 100%,
100% 0,
0 0,
0 50%,
borderWidth 50%,
quadrant2,
quadrant1,
quadrant4,
quadrant3,
borderWidth 50%,
0 50%);
最终效果如下:
渐变-边框-圆角【clip-path】
宽度(px):
高度(px):
背景:
圆角(px):
内角光滑度:
框宽(px):
效果是实现了,毕竟还是随手写的版本,bug啥的之类也是有的,这个轨迹算法也不是最牢靠的,这些就留给其他人解决了,哈哈哈哈哈哈。
奇奇怪怪的效果图: