仿 Tailwind CSS 官网首页 一个 button 的变化动画
先来看一下 tailwind CSS
官网这个动画的效果. 模仿这个动画可以学到的是定义和使用 CSS
变量以及在 JavaScript
中操作修改 CSS
变量. 在之前的交互动画模仿中, 借用了 <input type="radio">
, 而这次则改用 <input type="checkbox">
下面是我模仿的结果
HTML
<div class="container flex">
<input type="checkbox" title="this input" name="input" id="input-switch">
<label for="input-switch">
<div class="switch">
<div class="button"></div>
</div>
</label>
</div>
因为开关是可以开也可以关, 所以不能用 radio
因为其开了再点就不会关. 所以改用 checkbox
CSS
- 定义两个变量, 分别表示开关的开关和默认的背景颜色, 重置样式, 定义一个
flex
的水平垂直居中布局:root { --radius: 20px; --bgColor: #fff; } * { padding: 0; margin: 0; } .flex { display: flex; justify-content: center; align-items: center; }
- 设置
container
容器的样式. 这里要使用之前定义的变量bgColor
, 给背景颜色的变化加上线性过渡.container { height: 100vh; background-color: var(--bgColor); transition: background-color .2s linear; }
- 设置开关默认的样式
border-radius: 9999px;
是为了使得按钮有💊的效果, 两端是圆的.
.switch { width: calc( var(--radius) * 2.2 ); height: calc( var(--radius) ); background-color: rgb(96, 211, 96); border-radius: 9999px; position: relative; padding: 2px; transition: background-color .2s linear; }
- 设置开关中圆点⚪的效果
- 注意其
absolute
定位, 将来要修改其left
控制其位置变化. 默认位置是靠左靠上2px
, 就是父元素的padding
大小. 📕注意:left
是相对于父元素的border
计算的, 所以要加上 父元素的padding
.button { height: var(--radius); width: var(--radius); border-radius: 50%; background-color: rgba(255, 255, 255, 0.9); transition: all .2s ease-in-out; position: absolute; left: 2px; top: 2px; }
- 注意其
- 设置
checkbox
效果- 默认是不显示
- 选中后修改按钮的背景色. 并且修改⚪的
left
, 为父元素的width
(📕注意width
不包括padding
) 减去自身宽度再加上padding
input[type="checkbox"] { display: none; } input[type="checkbox"]:checked + label .switch { background-color: #D10; } input[type="checkbox"]:checked + label .switch .button { left: calc( var(--radius) * 2.2 - var(--radius) + 2px ); }
JavaScript
使用 setProperty
修改颜色
document.getElementById('input-switch').addEventListener('click', (e) => {
if (e.target.checked) {
document.body.style.setProperty('--bgColor', 'rgb(17, 24, 39)');
} else {
document.body.style.setProperty('--bgColor', '#fff');
}
})
完整代码
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Switch</title>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="../css/font-awesome.css">
</head>
<body>
<div class="container flex">
<input type="checkbox" title="this input" name="input" id="input-switch">
<label for="input-switch">
<div class="switch">
<div class="button"></div>
</div>
</label>
</div>
<script>
document.getElementById('input-switch').addEventListener('click', (e) => {
if (e.target.checked) {
document.body.style.setProperty('--bgColor', 'rgb(17, 24, 39)');
} else {
document.body.style.setProperty('--bgColor', '#fff');
}
})
</script>
</body>
</html>
CSS
:root {
--radius: 20px;
--bgColor: #fff;
}
* {
padding: 0;
margin: 0;
}
.container {
height: 100vh;
background-color: var(--bgColor);
transition: background-color .2s linear;
}
.flex {
display: flex;
justify-content: center;
align-items: center;
}
.switch {
width: calc( var(--radius) * 2.2 );
height: calc( var(--radius) );
background-color: rgb(96, 211, 96);
border-radius: 9999px;
position: relative;
padding: 2px;
transition: background-color .2s linear;
}
.button {
height: var(--radius);
width: var(--radius);
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.9);
transition: all .2s ease-in-out;
position: absolute;
left: 2px;
top: 2px;
}
input[type="checkbox"] {
display: none;
}
input[type="checkbox"]:checked + label .switch {
background-color: #D10;
}
input[type="checkbox"]:checked + label .switch .button {
left: calc( var(--radius) * 2.2 - var(--radius) + 2px );
}
谢谢你看到这里😀