- 其实我更想去找UI切图,充当背景图搞定
- 一方面切图确实可以解决这类问题,但另一方面切图自然而然占据了打包体积,包括http资源的请求,最主要定制化受限,如果切图自带弧边的阴影,而且如果连带主体内容都进入那样真就很麻烦
- 作为前端小朋友,自然而然用代码方式实现更加优雅
- 预览地址
什么是弧边选项卡
-
弧边选项卡的案例我下面截两张图,应该就一目了然了
-
12306车票
-
个人所得税
如何实现
这里需要说一个css3特性
radial-gradient
,从MDN上拷贝一段话是这么说的
radial-gradient()
CSS 函数创建一个图像,该图像由从原点辐射的两种或多种颜色之间的渐进过渡组成,其形状可以是圆形或椭圆形。函数的结果是<gradient>
数据类型的对象,此对象是一种特殊的<image>
类型。
/* 在容器中心的渐变,从红色开始,变成蓝色,最后变成绿色 */
radial-gradient(circle at center, red 0, blue, green 100%)
实现效果
代码
<div class="outer">
<div class="g-container">
<div class="g-item g-inner active"></div>
<div class="g-item g-after"></div>
<div class="g-inner-text">选项卡1</div>
<div class="g-after-text">选项卡2</div>
</div>
<div class="content-box">
<div class="content">这是选项卡1的内容</div>
<div class="content hide">这是选项卡2的内容</div>
</div>
</div>
.outer {
--active-color: #fff;
--default-color: #eee;
margin: 20px auto;
filter: drop-shadow(0 0 10px rgba(0, 0, 0, 0.1));
width: 300px;
border-radius: 10px;
overflow: hidden;
}
.g-container {
position: relative;
width: 300px;
height: 50px;
border-radius: 10px 10px 0 0;
overflow: hidden;
cursor: pointer;
background: var(--default-color);
}
.g-item {
position: absolute;
width: 150px;
height: 50px;
background: var(--default-color);
transition: all 0.3s linear;
}
.g-inner {
top: 0;
left: 0;
border-radius: 0 20px 0 20px;
transform: perspective(40px) scaleX(1.4) scaleY(1.5) rotateX(20deg)
translate(-10px, 0);
transform-origin: 50% 100%;
}
.g-inner.active,
.g-after.active {
background: var(--active-color);
z-index: 10;
}
.g-inner.active::before {
background: radial-gradient(
circle at 100% 0,
transparent,
transparent 9.5px,
var(--active-color) 10px,
var(--active-color)
);
}
.g-inner::before {
content: "";
position: absolute;
right: -10px;
width: 10px;
height: 10px;
top: 40px;
background: radial-gradient(
circle at 100% 0,
transparent,
transparent 9.5px,
var(--default-color) 10px,
var(--default-color)
);
}
.g-after {
top: 0;
right: 0;
border-radius: 20px 0 20px 0;
transform: perspective(40px) scaleX(1.4) scaleY(1.5) rotateX(20deg);
transform-origin: 50% 100%;
}
.g-after.active::before {
background: radial-gradient(
circle at 0 0,
transparent,
transparent 9.5px,
var(--active-color) 10px,
var(--active-color)
);
}
.g-after::before {
content: "";
position: absolute;
left: -10px;
top: 40px;
width: 10px;
height: 10px;
background: radial-gradient(
circle at 0 0,
transparent,
transparent 9.5px,
var(--default-color) 10px,
var(--default-color)
);
}
.g-inner-text,
.g-after-text {
position: absolute;
width: 150px;
height: 50px;
line-height: 50px;
text-align: center;
}
.g-inner-text {
top: 0;
left: 0;
z-index: 10;
}
.g-after-text {
top: 0;
right: 0;
z-index: 10;
}
.content-box {
width: 100%;
background: #fff;
transition: all 0.3s linear;
}
.content-box .content {
padding: 20px;
box-sizing: border-box;
width: 100%;
}
.content-box .content.hide {
display: none;
}
const oContaoner = document.querySelector(".g-container");
const leftItem = document.querySelector(".g-inner");
const rightItem = document.querySelector(".g-after");
const allContantNodes = document.querySelectorAll(".content");
function setContentDisplayStatus(_index) {
[...allContantNodes].forEach((c, index) => {
!c.classList.contains("hide") && c.classList.add("hide");
if (index === _index) {
c.classList.remove("hide");
}
});
}
oContaoner.addEventListener(
"click",
(e) => {
if (e.target.classList.contains("g-inner-text")) {
!leftItem.classList.contains("active") &&
leftItem.classList.add("active");
rightItem.classList.remove("active");
setContentDisplayStatus(0);
} else {
!rightItem.classList.contains("active") &&
rightItem.classList.add("active");
leftItem.classList.remove("active");
setContentDisplayStatus(1);
}
},
false
);