1、完整代码及样式示例

1.1. 渐变色 圆角/倒角 效果图

圆角

倒角

1.2. 渐变色 圆角/倒角 完整示例代码

渐变色色值:linear-gradient(270deg,rgba(34,117,211,1) 0%,rgba(14,244,243,1) 49%,rgba(34,117,211,1) 100%)

边宽:5px

宽:300px

高:150px

圆角值: 左上25px 右上30px 右下35px 左下40px

类型:圆角(若想要查看倒角样式,将borderType设置为chamfer即可)

2、前景提要

圆角渐变色边框不支持圆角

 1.fillet-gradient-color-box {
 2  display: flex;
 3  justify-content: center;
 4  align-items: center;
 5  width: 400px;
 6  height: 200px;
 7
 8  border: 1px solid transparent;
 9  border-image: linear-gradient(270deg,rgba(34,117,211,1) 0%,rgba(14,244,243,1) 49%,rgba(34,117,211,1) 100%) 1;
10  border-image-slice: 1;
11}

圆角纯色边框不支持渐变色

 1.fillet-pure-color-box {
 2  border: 1px solid #9ba2b0;
 3  border-radius: 20;
 4}

所以当我们需要满足既要**支持圆角**,又要**支持渐变色**的时候,就没有直接可以使用的css样式可以实现

圆角背景色设置渐变,after切割出圆角效果

【注】这种效果的缺陷是背景颜色不能有透明度,不然被叠加遮盖住的_background-image_颜色就会显示出来

 1.border-radius-demo {
 2  width: 400px;
 3  height: 400px;
 4
 5  position: relative;
 6  display: flex;
 7  justify-content: center;
 8  align-items: center;
 9
10  background-image: linear-gradient(270deg,rgba(34,117,211,1) 0%,rgba(14,244,243,1) 49%,rgba(34,117,211,1) 100%);
11  border-radius: 25px 30px 35px 40px;
12}
13.border-radius-demo:after {
14  content: "";
15  position: absolute;
16  left: 5px;
17  top: 5px;
18  z-index: 10;
19  width: calc(100% - 10px);
20  height: calc(100% - 10px);
21  border-radius: 25px 30px 35px 40px;
22  background-color: red;
23}

倒角结合边框配置单纯切割图形实现的倒角,会出现切割部分没有边的问题

【注】一下这种矩形裁切方式,会将四个角裁去的部分中边框的部分同样裁去,最终并不是想要实现的效果

 1.chamfer-gradient-color-box {
 2  width: 400px;
 3  height: 200px;
 4
 5  border: 3px solid transparent;
 6  border-image: linear-gradient(270deg,rgba(34,117,211,1) 0%,rgba(14,244,243,1) 49%,rgba(34,117,211,1) 100%) 1;
 7  border-image-slice: 1;
 8  background-color: rgb(103, 235, 63);
 9  clip-path: polygon(15px 0, calc(100% - 15px) 0, 100% 15px, 100% calc(100% - 5px), calc(100% - 15px) 100%,15px 100%, 0 calc(100% - 15px), 0 15px);
10}
11.chamfer-pure-color-box {
12  width: 400px;
13  height: 200px;
14  
15  border: 3px solid #9ba2b0;
16  border-radius: 20;
17  background-color: rgb(127, 255, 212);
18  clip-path: polygon(15px 0, calc(100% - 15px) 0, 100% 15px, 100% calc(100% - 15px), calc(100% - 15px) 100%,15px 100%, 0 calc(100% - 15px), 0 15px);
19}

3、实现方法及逻辑

通过CSS样式中的clip-path样式,结合dom元素的after进行叠加遮盖,实现 渐变色 圆角/倒角 边框 的效果

3.1. 内圆 圆角值计算逻辑图解

3.2. CSS绘制逻辑图解

3.3. 绘制外圈圆角矩形路径(按照逆时针方向绘制)

 1const createOuterRoundedRectPath = (params) => {
 2  const { x, y, width, height, borderRadius } = params;
 3  return (
 4    "M " +
 5    x +
 6    "," +
 7    (y + height / 2 + (height / 2 - borderRadius.leftBottom)) +
 8    " a " +
 9    borderRadius.leftBottom +
10    "," +
11    borderRadius.leftBottom +
12    " 0 0 0 " +
13    borderRadius.leftBottom +
14    "," +
15    borderRadius.leftBottom +
16    " h " +
17    (width - (borderRadius.rightBottom + borderRadius.leftBottom)) +
18    " a " +
19    borderRadius.rightBottom +
20    "," +
21    borderRadius.rightBottom +
22    " 0 0 0 " +
23    borderRadius.rightBottom +
24    "," +
25    borderRadius.rightBottom * -1 +
26    " v " +
27    (height - (borderRadius.rightBottom + borderRadius.rightTop)) * -1 +
28    " a " +
29    borderRadius.rightTop +
30    "," +
31    borderRadius.rightTop +
32    " 0 0 0 " +
33    borderRadius.rightTop * -1 +
34    "," +
35    borderRadius.rightTop * -1 +
36    " h " +
37    (width - (borderRadius.rightTop + borderRadius.leftTop)) * -1 +
38    " a " +
39    borderRadius.leftTop +
40    "," +
41    borderRadius.leftTop +
42    " 0 0 0 " +
43    borderRadius.leftTop * -1 +
44    "," +
45    borderRadius.leftTop +
46    " z"
47  );
48};

3.4. 绘制内圈圆角矩形路径(按照顺时针方向绘制)

 1const createInnerRoundedRectPath = (params) => {
 2  const { x, y, width, height, borderRadius } = params;
 3  return (
 4    "M " +
 5    (x + borderRadius.leftTop) +
 6    "," +
 7    y +
 8    " h " +
 9    (width - (borderRadius.rightTop + borderRadius.leftTop)) +
10    " a " +
11    borderRadius.rightTop +
12    "," +
13    borderRadius.rightTop +
14    " 0 0 1 " +
15    borderRadius.rightTop +
16    "," +
17    borderRadius.rightTop +
18    " v " +
19    (height - (borderRadius.rightBottom + borderRadius.rightTop)) +
20    " a " +
21    borderRadius.rightBottom +
22    "," +
23    borderRadius.rightBottom +
24    " 0 0 1 " +
25    borderRadius.rightBottom * -1 +
26    "," +
27    borderRadius.rightBottom +
28    " h " +
29    (width - (borderRadius.leftBottom + borderRadius.rightBottom)) * -1 +
30    " a " +
31    borderRadius.leftBottom +
32    "," +
33    borderRadius.leftBottom +
34    " 0 0 1 " +
35    borderRadius.leftBottom * -1 +
36    "," +
37    borderRadius.leftBottom * -1 +
38    " v " +
39    (height - (borderRadius.leftBottom + borderRadius.leftTop)) * -1 +
40    " a " +
41    borderRadius.leftTop +
42    "," +
43    borderRadius.leftTop +
44    " 0 0 1 " +
45    borderRadius.leftTop +
46    "," +
47    borderRadius.leftTop * -1 +
48    " z"
49  );
50};

3.5. 绘制外圈倒角矩形路径(按照逆时针方向绘制)

 1const createOuterAngleRectPath = (params) => {
 2  const { x, y, width, height, borderRadius } = params;
 3  return (
 4    "M " +
 5    x +
 6    "," +
 7    (y + height / 2 + (height / 2 - borderRadius.leftBottom)) +
 8    " l " +
 9    borderRadius.leftBottom +
10    "," +
11    borderRadius.leftBottom +
12    " h " +
13    (width - (borderRadius.rightBottom + borderRadius.leftBottom)) +
14    " l " +
15    borderRadius.rightBottom +
16    "," +
17    borderRadius.rightBottom * -1 +
18    " v -" +
19    (height - (borderRadius.rightBottom + borderRadius.rightTop)) +
20    " l " +
21    borderRadius.rightTop * -1 +
22    "," +
23    borderRadius.rightTop * -1 +
24    " h -" +
25    (width - (borderRadius.rightTop + borderRadius.leftTop)) +
26    " l " +
27    borderRadius.leftTop * -1 +
28    "," +
29    borderRadius.leftTop +
30    " z"
31  );
32};

3.6. 绘制内圈倒角矩形路径(按照顺时针方向绘制)

 1const createInnerAngleRectPath = (params) => {
 2  const { x, y, width, height, borderRadius } = params;
 3  return (
 4    "M " +
 5    (x + borderRadius.leftTop) +
 6    "," +
 7    y +
 8    " h " +
 9    (width - borderRadius.rightTop - borderRadius.leftTop) +
10    " l " +
11    borderRadius.rightTop +
12    "," +
13    borderRadius.rightTop +
14    " v " +
15    (height - borderRadius.rightBottom - borderRadius.rightTop) +
16    " l " +
17    borderRadius.rightBottom * -1 +
18    "," +
19    borderRadius.rightBottom +
20    " h " +
21    -1 * (width - borderRadius.leftBottom - borderRadius.rightBottom) +
22    " l " +
23    borderRadius.leftBottom * -1 +
24    "," +
25    borderRadius.leftBottom * -1 +
26    " v " +
27    -1 * (height - borderRadius.leftTop - borderRadius.leftBottom) +
28    " l " +
29    borderRadius.leftTop * -1 +
30    "," +
31    borderRadius.leftTop +
32    " z"
33  );
34};

3.7. 结合内圈&外圈return的路径,返回clip-path样式path的路径数据

【注】这里传递参数时,需要对圆角大小进行限制,不能超过宽高最小值的一半

 1const getAssemblePath = (outerParams, innerParams, type) => {
 2  
 3  const outerRoundPath =
 4    type === "fillet"
 5      ? createOuterRoundedRectPath(outerParams)
 6      : createOuterAngleRectPath(outerParams);
 7  
 8  const innerRoundPath =
 9    type === "fillet"
10      ? createInnerRoundedRectPath(innerParams)
11      : createInnerAngleRectPath(innerParams);
12  return {
13    borderPath: `${outerRoundPath} ${innerRoundPath}`,
14    bgPath: `${outerRoundPath}`,
15  };
16};
17
18const handleCalculatePath = (
19  borderRadius,
20  type,
21  strokeWidth,
22  { boxWidth, boxHeight }
23) => {
24  
25  let newBorderRadius = {
26    leftTop: Math.min(borderRadius.leftTop, Math.min(boxWidth, boxHeight) / 2),
27    rightTop: Math.min(
28      borderRadius.rightTop,
29      Math.min(boxWidth, boxHeight) / 2
30    ),
31    rightBottom: Math.min(
32      borderRadius.rightBottom,
33      Math.min(boxWidth, boxHeight) / 2
34    ),
35    leftBottom: Math.min(
36      borderRadius.leftBottom,
37      Math.min(boxWidth, boxHeight) / 2
38    ),
39  };
40  const outerParams = {
41    x: 0,
42    y: 0,
43    width: boxWidth,
44    height: boxHeight,
45    borderRadius: newBorderRadius,
46  };
47  const innerParams = {
48    x: strokeWidth,
49    y: strokeWidth,
50    width: boxWidth - strokeWidth * 2,
51    height: boxHeight - strokeWidth * 2,
52    borderRadius: {
53      leftTop: newBorderRadius.leftTop + (Math.sqrt(2) - 2) * strokeWidth,
54      rightTop: newBorderRadius.rightTop + (Math.sqrt(2) - 2) * strokeWidth,
55      rightBottom:
56        newBorderRadius.rightBottom + (Math.sqrt(2) - 2) * strokeWidth,
57      leftBottom: newBorderRadius.leftBottom + (Math.sqrt(2) - 2) * strokeWidth,
58    },
59  };
60  const path = getAssemblePath(outerParams, innerParams, type).borderPath;
61  const bgPath = getAssemblePath(outerParams, innerParams, type).bgPath;
62
63  return { path, bgPath };
64};

3.8. 生成CSS样式

 1const handleDrawGraph = (
 2  borderRdius,
 3  type,
 4  borderWidth,
 5  boxWidth,
 6  boxHeight,
 7  borderColor
 8) => {
 9  const { path, bgPath } = handleCalculatePath(
10    borderRadius,
11    type,
12    borderWidth,
13    {
14      boxWidth,
15      boxHeight
16    }
17  );
18  return {
19    "--custom-box-clip-path": `path('${path}')`,
20    "--custom-box-clip-path-bg-path": `path('${bgPath}')`,
21    "--custom-box-clip-path-bg-color": borderColor
22  }
23}
 1.custom-box {
 2  position: relative;
 3  width: 100%;
 4  height: 100%;
 5  clip-path: var(--custom-box-clip-path-bg-path);
 6  &::after {
 7    position: absolute;
 8    left: 0;
 9    top: 0;
10    z-index: -1;
11    width: 100%;
12    height: 100%;
13    background: var(--custom-box-clip-path-bg-color);
14    clip-path: var(--custom-box-clip-path);
15  }
16}

通过以上设置就可以实现 渐变色/纯色+圆角/倒角 的样式效果

个人笔记记录 2021 ~ 2025