渐变色+边框+圆角

核心Css:clip-path

核心js:计算四个象限的内角路径

前言

设计师搞了一个酷炫的渐变圆角边框。然而,web端的css,边框可以渐变,也可以圆角,却不能渐变+圆角。网络上找了蛮多解决方案的。大体有以下几类:

  1. 外层+内层。外层border-radius,内层border-radius。内层再填充一个背景色,使得外层看起来像被镂空。缺点就是内部无法透明
  2. 直接使用边框渐变,然后父级加一个border-radius。缺点就是内圆角是直角。
  3. 使用mask,实现准备好一个素材图片,这个素材就是你想要的边框轮廓。缺点就是大小固定的,不能自适应。
  4. 直接使用图片。

总之,找了一圈,没找到符合心意的。自己尝试设想了方案:

  1. 使用clip-path,把边框路径计算出来,裁剪。
  2. 使用mix-blend-mode,混合模型下,实现反向选择那样的效果(ps:canvas中可以,但是css中没找到这样的混合模式,改方案嗝屁了)
  3. 使用element(),但是这个东西,目前主流浏览器没几个实现,本来这个结合mask就很简单。
  4. html2canvas+mask,要下载插件,就动了个脑子,没有去具体实践。
  5. canvas或者svg直接绘制,太懒了,想了想就算了。 

最后决定使用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=W+r 

R:border-radius,外层圆的半径

W:border-width,指定的边框宽度

r:内层圆的半径

 以第一象限为例

\Delta x=r*\cos \left ( \theta \right )

\Delta y= r*\sin \left ( \theta \right )

可以计算出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啥的之类也是有的,这个轨迹算法也不是最牢靠的,这些就留给其他人解决了,哈哈哈哈哈哈。

奇奇怪怪的效果图:

渐变色+边框+圆角_第1张图片  大家自己慢慢试,如果采用了,记得修bug,我溜了。 

 

你可能感兴趣的:(css,css,前端)