Sliding bottom tab 仿 bilibili 安卓客户端滑动 tab
先看效果
😄第一次做效果,咱就是没写过,所以写来看看,顺便把基础知识练习一下
HTML
<nav>
<div class="container">
<input type="radio" name="nav" id="nav-song" checked>
<label for="nav-song">简介</label>
<input type="radio" name="nav" id="nav-video">
<label id="nav-video-lable" for="nav-video">评论 1104</label>
<input type="radio" name="nav" id="nav-live">
<label id="nav-live-lable" for="nav-live">点我发弹幕</label>
<span class="glider"></span>
</div>
</nav>
个人觉得代码部分不是很难, 但也有几个地方需要像我一样的小白注意
- 第一就是使用
<input type="radio">
做选项卡之间互斥的情况, 并且使用checked
默认选中某一项 - 隐藏
<input>
而使用<label>
作为选项卡显示的汉字;
CSS
- 整体, 取消所有的
padding
, 和margin
, 并设置背景颜色和字体* { padding: 0; margin: 0; font-family: Helvetica, sans-serif; background-color: rgba(#e6eef9, 0.5); }
- 设置导航, 页面居中
vh
: 这个单位的意思是整个视窗高度的1%
, 所以100vh
就是占满整个高度. 对应的当然有vw
整个视窗宽度的1%
,nav { display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #F3F4F6; }
- 设置具体的
tab
标签
要求很简单, 只占整个nav
的80%
, 占多少都行, 这主要是为了截图方便🤭
positive
定位为了方便滑动条的定位nav .container { display: flex; justify-content: space-evenly; align-items: center; background-color: #fff; padding: 4px; position: relative; width: 80%; }
- 隐藏
radio
, 同时设置当这个radio
状态为checked
时, 对应的label
颜色的改变 ( 使用了相邻兄弟选择器+
)input[type="radio"] { display: none; } input[type="radio"]:checked + label { color: #185ee0; }
- 设置
label
, 居中显示label { display: flex; justify-content: center; align-items: center; }
- 设置滑动条
注意absolute
定位使得<span>
变为块元素, 所以高度可以生效.glider { position: absolute; bottom: 0; height: 2px; background-color: #185ee0; transition: all .2s ease-in-out; }
JavaScript
就是, 刚加载的时候让滚动条处于第一个 tab
下面, 然后每次点击时, 调整滚动条的宽度和位置即可, 记得 offsetWidth
和 offsetLeft
返回的是 number
, 所以最后要加上 px
let glider = document.querySelector('.glider');
let firstFlag = true;
document.querySelectorAll('label').forEach((label) => {
if (firstFlag) {
glider.style.width = label.offsetWidth + 'px';
glider.style.left = label.offsetLeft + 'px';
firstFlag = false;
}
label.addEventListener('click', (e) => {
glider.style.width = e.target.offsetWidth + 'px';
glider.style.left = e.target.offsetLeft + 'px';
});
});
最后放上所有代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav>
<div class="container">
<input type="radio" name="nav" id="nav-song" checked>
<label for="nav-song">简介</label>
<input type="radio" name="nav" id="nav-video">
<label for="nav-video">评论 1104</label>
<input type="radio" name="nav" id="nav-live">
<label for="nav-live">点我发弹幕</label>
<span class="glider"></span>
</div>
</nav>
<script>
let glider = document.querySelector('.glider');
let firstFlag = true;
document.querySelectorAll('label').forEach((label) => {
if (firstFlag) {
glider.style.width = label.offsetWidth + 'px';
glider.style.left = label.offsetLeft + 'px';
firstFlag = false;
}
label.addEventListener('click', (e) => {
glider.style.width = e.target.offsetWidth + 'px';
glider.style.left = e.target.offsetLeft + 'px';
});
});
</script>
</body>
</html>
* {
padding: 0;
margin: 0;
font-family: Helvetica, sans-serif;
background-color: rgba(#e6eef9, 0.5);
}
nav {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #F3F4F6;
}
nav .container {
display: flex;
justify-content: space-evenly;
align-items: center;
background-color: #fff;
/* border-radius: 9999px; */
padding: 4px;
position: relative;
width: 80%;
}
input[type="radio"] {
display: none;
}
input[type="radio"]:checked + label {
color: #185ee0;
}
.glider {
position: absolute;
bottom: 0;
height: 2px;
background-color: #185ee0;
transition: all .2s ease-in-out;
}
label {
display: flex;
justify-content: center;
align-items: center;
}