切换开关(toggle switch)是常用的UI元素,和按钮不同,开关可以在“开”和“关”2个状态间切换。目前最常见的开关是这种圆形风格的:(若干年后就不一定了)
网上也有很多用CSS和HTML实现的例子,但都不完美,因为往往需要多个html元素配合才能实现这种开关,如何用一个最传统的<input type="checkbox">元素实现呢?最近终于找到了方法:使用CSS的伪元素 :before 和 :after 来作为额外的元素,用纯CSS实现一个最简洁又好看、一个元素搞定的开关。首先,想要使用这2个伪元素,得先设置 appearance: none,禁用浏览器默认的开关效果。开关底座的样式:
input[type="checkbox"] {
appearance: none;
width: 64px;
height: 32px;
position: relative;
border-radius: 16px;
cursor: pointer;
background-color: #777;
}
加上2个伪元素,总共逻辑上有3个元素,分别是开关的底座、把柄、文字。开关的把柄就是图中的小圆(高度略小于底座),用 :before 实现:
input[type="checkbox"]:before {
content: "";
position: absolute;
width: 28px;
height: 28px;
background: white;
left: 2px;
top: 2px;
border-radius: 50%;
transition: left cubic-bezier(0.3, 1.5, 0.7, 1) 0.3s;
}
为了实现开关切换时的惯性效果,即把柄滚到对端以后稍微越界然后被拉回,我们用立方bezier曲线来表示,其中横轴是时间,纵轴是把柄位置,从曲线中可看到,先做减速运动,然后在极大值处越界,最后被缓缓拉回总共0.3秒的动画。
最后是背景字,我们用 :after 来表示,字里行间距设置妥当,z轴位置必须处于底座和把柄之间,“开”和“关”位于两端:
input[type="checkbox"]:after {
content: "开 关";
text-indent: 12px;
word-spacing: 4px;
display: inline-block;
white-space: nowrap;
color: white;
font: 14px/30px monospace;
font-weight: bold;
}
于是就实现了一个最简洁的开关:
引入这个行内联元素只需要一个html元素即可,语义性很好同时能利用自身的checked属性:
<input type="checkbox" onchange="alert(this.checked)"/>
最后再增加一些锦上添花的效果,利用 :checked 选择器表示“开”的状态,通过 :hover 选择器表示光标悬浮的状态:
input[type="checkbox"]:hover:before {
box-shadow: inset 0px 0px 5px 0px black;
}
input[type="checkbox"]:checked {
background-color: limegreen;
}
input[type="checkbox"]:checked:before {
left: 34px;
}
input[type="checkbox"]:checked:after {
color: black;
}
使用的时候,将上述所有的css汇聚到<style>中,然后直接使用<input type="checkbox" />就可以了,既简单又漂亮,哪用得着那么多UI库啊,现在CSS越来越强大了,很多UI效果都不需要JS就能轻松实现,这个开关的最终效果动图如下: