大家好,我是 Steven。
这期我们会用 CSS 制作一个 iOS 的开关按钮,先看看制作的成品:
点击一下会打开,再点击一下会关闭。但原来它还有一个小细节,就是长按的时候里面的圆形会拉长,放手后会变回圆形:
还有就是现在流行夜间模式 (Dark Mode),这个按钮会因应系统的色调设定改变,试试将系统改变为夜间模式:
按钮的背景颜色就会改为深灰色。
在这个案例中,我们会学习到如何使用 CSS 建构这个按钮,过程中会运用到 CSS 的变数,以及如何判断系统的色调设定,套用夜间模式时的 CSS 样式。
分析按钮
首先看看这个 iOS 开关按钮所有状态的样式,这是我从 iOS 中截图,然后在 Sketch 中按一比一绘画的。
左边是 Light Mode 下的样式,而右边是 Dark Mode 下的样式。Light Mode 与 Dark Mode 下的开关按钮,就只有在关闭状态时的灰色不同,Light Mode 下的是浅灰色,Dark Mode 下的是深灰色。
由于建构这个按钮时使用到的数值比较多,例如按钮的宽度与高度,里面圆形在正常与拉长状态下的大小,以及绿色、灰色、深灰色等多种颜色。如果可以将这些设定值都放到同一个地方,那么将来要改变这个按钮的参数也很容易,这就可以用上 CSS 变数。
CSS 变数的定义方法,是使用两个 -
符号 (--
) 作起首,然后就可以定义变数的名称,这里我预先规划好了所有会定义的变数名称:
--button-width
与--button-height
按钮的宽度与高度--toggle-diameter
里面圆形的直径- 红色这个
--button-toggle-offset
是按钮与里面圆形的间距,这可以通过--button-height
减去--toggle-diameter
再除以2
计算出来 --toggle-shadow-offset
里面圆形的阴影打多大--color-grey
按钮的浅灰色背景--toggle-wider
里面圆形在长按的状态下拉宽后的宽度--color-dark-grey
夜间模式时的深灰色背景--color-green
按钮在开启状态时的绿色背景
所有将会定义的变数以及设定值已整理到这个列表中:
定义 CSS 变数
然后我们就根据这个列表,将所有变数都定义到 CSS 中。首先定义一个名为 :root
的选择器,:root
可以理解为最顶层,将 CSS 变数定义在这里,代表可以在任何任置都存取得到。
然后一一输入变数名称与它的值。--button-toggle-offset
这个值是通过 --button-height
与 --toggle-diameter
计算出来的。先通过 var(--button-height)
获得 --button-height
的值,再通过 var(--toggle-diameter)
获得 --toggle-diameter
的值,由于要将它们相减,所以在外层套用 calc()
函数,两个变数之间再加上减号,由于先乘除后加减的关系,将相减的运算式再加一层括号,然后在 calc()
的关括号前加上 / 2
就可以了。
现在变数已定义好了,接着下来就开始建构这个按钮。
建构开关按钮
在 HTML 内新增一个 <span>
标签,然后在 CSS 中加入 span
选择器,display
是 inline-block
。宽度 width
是 var(--button-width)
,而高度 height
是 var(--button-height)
。
背景颜色 background-color
是 var(--color-grey)
。圆角 border-radius
是按钮高度的一半,所以先用 var(--button-height)
获取它的值,再通过 calc()
包着它,然后除以 2。
而里面的圆形因为会使用 position: absolute
去定位,所以这里会将 position
设定为 relative
。
将这个按钮在页面中上下左右居中,加入 body
选择器,display
设定为 flex
,justify-content
与 align-items
设定为 center
,min-height
设定为 100vh
。
然后设定里面的圆形,我会使用 Pseudo Selector(伪类)。加入 span::after
选择器,content
设定为空白字串,这样浏览器才会将它显示出来。
然后将 display
设定为 inline-block
,宽度与高度设定为 --toggle-diameter
,背景颜色设定为白色,然后 border-radius
是直径的一半,所以是 calc()
,里面填上 var(--toggle-diameter)
然后除 2。
现在圆形已经显示了出来,将 position
设定为 absolute
,再将 top
设定为 --button-toggle-offset
,对于左边的偏移距离,为了方便稍后做动画,我会使用 transform
的 translateX()
将它移动,设定值同样是 var(--button-toggle-offset)
。
再设定阴影,box-shadow
的 X 方向距离是 var(--toggle-shadow-offset)
,Y 方向是 0,然后 blur(阴影的模糊)设定为距离的 4 倍,所以是 calc(var(--toggle-shadow-offset) * 4)
。
最后,颜色设定为 10% 半透明的黑色,使用 rgba(0, 0, 0, .10)
就可以了。
处理按钮点击
处理这个按钮的点击事件,并不需要使用到 JavaScript,只需运用 HTML 的表单元素 checkbox 配合 CSS 即可。
在 HTML 中新增 <label>
标签,里面加上 <input type="checkbox">
,由于按钮被 <label>
包着的关系,现在点击这个按钮就可以同时点击到 checkbox。
然后通过 input[type="checkbox"]:checked + span
,控制 checkbox 在勾选状态下按钮的样式。先把背景颜色设定为 var(--color-green)
。现在点击按钮,背景颜色就会因应 checkbox 的勾选状态而改变。
再调整里面的圆形的位置,通过 input[type="checkbox"]:checked + span::after
,将 transform
设定为 translateX()
,按钮宽度减去里面圆形的直径,再减去按钮与圆形间的距离。即 calc()
,var(--button-width)
减去 var(--toggle-diameter)
,再减去 var(--button-toggle-offset))
:
再将阴影调整一下,当圆形在右边的时候,阴影改为左边,复制一下本身的 box-shadow
设定,然后将 var(--toggle-shadow-offset)
乘以 -1
即可:
接下来在 span
与 span::after
都加上 transition
设定,加入 transition: .3s all ease-in-out;
,为背景颜色与圆形加上平滑过渡的动画:
现在可以将 checkbox
的 display
设定为 none
将其隐藏:
处理长按时的效果
现在开关按钮已经基本完成,接下来加上长按状态下的拉长效果。
按下的状态可以通过 :active
去控制,加上 input[type="checkbox"]:active + span::after
,即按下 checkbox 时,里面的圆形的样式。将 width
设定为 var(--toggle-wider)
:
左至右的效果没有问题,而右至左则超出了按钮的范围,这需要再处理 input[type="checkbox"]:checked:active + span::after
,即 checkbox 在已勾选的状态下,长按时里面的圆形的样式。
超出按钮范围的原因是,按钮的宽度改变了,所以需要把它向左移一点。将 transform
设定为 translateX()
,按钮宽度 --button-width
减去加长了的圆形宽度 --toggle-width
,再减去按钮与圆形之间的距离 --button-toggle-offset
:
这样就完成了。
夜间模式
最后,加上夜间模式的处理。我们可以通过 CSS 的 Media Query @media (prefers-color-scheme: dark)
去判断当前的系统是不是启用了夜间模式。
而在 Media 区块内的,就是夜间模式下会套用的 CSS 样式设定,首先将 body
的背景颜色设定为深灰色 #1C1C1E
,再将 span
按钮的背景颜色设定为深灰色 var(--color-dark-grey)
。
我们来看看这个案例的完成效果
以上,就是这期要介绍的全部内容。
这个案例的源代码在 codepen.io/stevenlei/p…
- B站: space.bilibili.com/451368848
- YouTube: youtube.com/codingstart…
- 掘金: juejin.cn/user/249773…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!