使用css的mask属性结合径向渐变(radial-gradient)实现特殊切角


theme: juejin

这是群有的一个需求,一开始我还觉得,这啥,不挺容易的嘛,后来仔细一看才发现,看似简单的东西,实际也并不简单

需求

原需求是实现这种风格的标签页

image.png

逐步实现

第一次实现

粗略一看,这种东西很容易呀,不就是每个tab的顶部的两个角是圆角嘛,刷刷几下,实现的效果如下:

image.png

<template>
  <ul class="demoA">
    <li class="one">A</li>
    <li class="two active">激活</li>
    <li class="three">C</li>
    <li class="four">D</li>
  </ul>
</template>
<style scoped>
.demoA {
  margin: 0 0 20px 40px;
  padding: 0;
  display: flex;
  position: relative;
}
.demoA li {
  position: relative;
  list-style-type: none;
  margin: 0;
  padding: 0;
  width: 150px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  /* 设置顶部的两个角为圆角 */
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
  color: white;
}

.demoA li {
  /* 保持每个个li有一点点重叠 */
  margin-right: -4px;
}
/* 激活状态的选项卡 */
.demoA li.active {
  z-index: 20;
}
.demoA .one {
  background-color: red;
  /* 默认盖住的效果是从左到右,左边的盖住了右边的,而实际效果图是右边的盖住了左边的,所以用z-index递减的方式实现 */
  z-index: 4;
}
.demoA .two {
  background-color: green;
  z-index: 3;
}
.demoA .three {
  background-color: blue;
  z-index: 2;
}
.demoA .four {
  background-color: orange;
  z-index: 1;
}
</style>

第二次实现

将第一次的效果和原图一对比,好像有点不一样呀,哦,是底部还有两个小脚脚。

image.png

既然发现了不同点,我微微一笑,标签项底部的两个角不就是两个三角形嘛,so…easy, 网上一搜css画三角形。于是实现效果如下

image.png

<template>
  <ul class="demoA">
    <li class="one">A</li>
    <li class="two active">激活</li>
    <li class="three">C</li>
    <li class="four">D</li>
  </ul>
</template>
<style scoped>
.demoA {
  margin: 0 0 20px 40px;
  padding: 0;
  display: flex;
  position: relative;
  /* 正方形旋转45度,再遮住一半就是三角形了 */
  overflow: hidden;
}
.demoA li {
  position: relative;
  list-style-type: none;
  margin: 0;
  padding: 0;
  width: 150px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  /* 设置顶部的两个角为圆角 */
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
  color: white;
}

.demoA li {
  /* 保持每个个li有一点点重叠 */
  margin-right: -4px;
  position: relative;
}

.demoA li::before {
  content: '';
  width: 10px;
  height: 10px;
  position: absolute;
  left: -5px;
  bottom: -5px;
  /* 正方形旋转45度,再遮住一半就是三角形了 */
  transform: rotate(45deg);
}
.demoA li::after {
  content: '';
  width: 10px;
  height: 10px;
  position: absolute;
  right: -5px;
  bottom: -5px;
  transform: rotate(45deg);
}
.demoA .one::before {
  background-color: red;
}
.demoA .one::after {
  background-color: red;
}
.demoA .two::before {
  background-color: green;
}
.demoA .two::after {
  background-color: green;
}
.demoA .three::before {
  background-color: blue;
}
.demoA .three::after {
  background-color: blue;
}
.demoA .four::before {
  background-color: orange;
}
.demoA .four::after {
  background-color: orange;
}
/* 激活状态的选项卡 */
.demoA li.active {
  z-index: 20;
}
.demoA .one {
  background-color: red;
  /* 默认盖住的效果是从左到右,左边的盖住了右边的,而实际效果图是右边的盖住了左边的,所以用z-index递减的方式实现 */
  z-index: 4;
}
.demoA .two {
  background-color: green;
  z-index: 3;
}
.demoA .three {
  background-color: blue;
  z-index: 2;
}
.demoA .four {
  background-color: orange;
  z-index: 1;
}
</style>

第三次实现

第二次实现完成之后,再对比一看,好像还是有点不一样,再仔细看看,哦,原来他底下两个脚不是两个纯粹的三角形,而是有点圆滑的过渡。这就是我的知识盲区了,怎么整?靠切图然后拼起来?好像也不行呀。果然是懵逼树下懵逼果,懵逼树下只有我。群里的Xc大佬好像实现了一个,要不我看看?保证,肯定只看一点点,就一点点。满怀期待的点开大佬发的链接,然后发现打不开?打不开?怎么能打不开呢!!!再看群消息,大佬撤回了?要不算了,反正也不是我的需求。不行!都搞半天了!不搞出来!睡不着!要不问大佬要代码?于是半夜群里呼叫大佬。大佬让我用梯子。没梯子咋整?算了?不行,我再试试,于是再次走上了疯狂搜索之路,终于找到了一篇文章 《基于CSS mask和clip-path实现切角的技巧 – 掘金 (juejin.cn)》好像可以,那就再试试。

image.png

image.png

解决方案简言之就是:使用mask结合radial-gradient,对底部两个脚的小方块的右上角和左上角,切除一个四分之一圆

image.png

<template>
  <ul class="demoA">
    <li class="one">A</li>
    <li class="two active">激活</li>
    <li class="three">C</li>
    <li class="four">D</li>
  </ul>
</template>

<style scoped>
.demoA {
  margin: 0 0 20px 40px;
  padding: 0;
  display: flex;
  position: relative;
  overflow: hidden;
}
.demoA li {
  position: relative;
  list-style-type: none;
  margin: 0;
  padding: 0;
  width: 150px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  /* 设置顶部的两个角为圆角 */
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
  color: white;
}

.demoA li {
  /* 保持每个个li有一点点重叠 */
  margin-right: -4px;
  position: relative;
}

.demoA li::before {
  content: '';
  width: 10px;
  height: 10px;
  position: absolute;
  left: -5px;
  bottom: -5px;
  /* 切个4分之一圆达到圆滑效果 */
  --mask: radial-gradient(5px at 0 0, #0000 98%, #000);
  -webkit-mask: var(--mask);
  mask: var(--mask);
}
.demoA li::after {
  content: '';
  width: 10px;
  height: 10px;
  position: absolute;
  right: -5px;
  bottom: -5px;
  /* 切个4分之一圆达到圆滑效果 */
  --mask: radial-gradient(5px at 100% 0, #0000 98%, #000);
  -webkit-mask: var(--mask);
  mask: var(--mask);
}
.demoA .one::before {
  background-color: red;
}
.demoA .one::after {
  background-color: red;
}
.demoA .two::before {
  background-color: green;
}
.demoA .two::after {
  background-color: green;
}
.demoA .three::before {
  background-color: blue;
}
.demoA .three::after {
  background-color: blue;
}
.demoA .four::before {
  background-color: orange;
}
.demoA .four::after {
  background-color: orange;
}
/* 激活状态的选项卡 */
.demoA li.active {
  z-index: 20;
}
.demoA .one {
  background-color: red;
  /* 默认盖住的效果是从左到右,左边的盖住了右边的,而实际效果图是右边的盖住了左边的,所以用z-index递减的方式实现 */
  z-index: 4;
}
.demoA .two {
  background-color: green;
  z-index: 3;
}
.demoA .three {
  background-color: blue;
  z-index: 2;
}
.demoA .four {
  background-color: orange;
  z-index: 1;
}
</style>

现在基本就和原图的效果一致了,底部两种角的实现效果有什么区别,看下面的对比图就很明确了

image.png

效果虽然实现了,但我对mask和径向渐变还不太了解,需要补充下相关知识:

基于CSS mask和clip-path实现切角的技巧 – 掘金 (juejin.cn)

10个demo示例学会CSS3 radial-gradient径向渐变 « 张鑫旭-鑫空间-鑫生活 (zhangxinxu.com)

客栈说书:CSS遮罩CSS3 mask/masks详细介绍 « 张鑫旭-鑫空间-鑫生活 (zhangxinxu.com)

(37条消息) CSS 的 radial-gradient() 径向渐变函数(带例子)_你好像很好吃a的博客-CSDN博客

最后的最后

前面的例子,底部的两个小脚,都是通过伪类实现的,但从原图看,是要能够动态增加tab的,同时不同tab的颜色也不一样,那么就不能再通过伪类来实现了,而应该在每个li中增加两个实际存在的元素,来实现底部的两个脚,然后再将这个li封装为一个组件颜色,就通过外部传入进来,最后再一起设置进去。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容