纯CSS模仿iOS中switch按钮的交互效果

502 阅读3分钟

使用到的知识点:

  • 在css中定义全局变量
  • calc函数
  • 伪类选择器结合input的各种状态控制
  • @media适配dark模式

定义css中用到的变量

在 :root{} 中,通过 --a-b的形式定义整个按钮中用到的一些布局和颜色值的变量

:root{
    /* 按钮宽度 */
    --button-width: 500px;
    /* 按钮高度 */
    --button-height: 295px;
    /* 里面圆形直径 */
    --toggle-diameter: 255px;
    /* 按钮与里面圆形之间的间距 */
    --button-toggle-offset: calc((var(--button-height) - var(--toggle-diameter)) / 2);
    /* 里面圆形阴影的大小 */
    --toggle-shadow-offset: 10px;
    /* 里面圆形在长按状态下的宽度 */
    --toggle-wider: 333px;
    /* 浅灰色 */
    --color-grey: #e9e9e9;
    /* 深灰色 */
    --color-dark-grey: #39393D;
    /* 绿色 */
    --color-green: #30d158;
  }

html部分

<label for="toggle">
  <input type="checkbox" id="toggle">
  <span></span>
</label>

直接用css去调整span的形态来构建按钮,跟checkbox一起放在一个label里,通过checkbox的状态改变来触发span的改变。

css部分

原始的样子

span{
    display: inline-block;
    width: var(--button-width);
    height: var(--button-height);
    background-color: var(--color-grey);
    border-radius: calc(var(--button-height) / 2);
    position: relative;
  }

  span::after{
    content: '';
    display: inline-block;
    width: var(--toggle-diameter);
    height: var(--toggle-diameter);
    background-color: white;
    border-radius: calc(var(--toggle-diameter) / 2);
    position: absolute;
    top: var(--button-toggle-offset);
    transform: translateX(var(--button-toggle-offset));
    box-shadow: var(--toggle-shadow-offset) 0 calc(var(--toggle-shadow-offset) * 4) rgba(0, 0, 0, 0.1);
  }
  
  body{
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh  ;
  }

按钮里面的圆形,直接使用span::after伪类来描述,此刻你会得到一个居中显示的没有啥交互的switch按钮

截屏2023-08-28 16.07.51.png

点击交互,让小圆形动起来,背景色改变,长按时小圆形变长等

 input:checked + span{
    background-color: var(--color-green);
 }

如果页面比较复杂,为了区分不同的input类型,应该用input[type='checkbox']来定位元素,这里因为只有一个input标签,就简单处理了。通过:check + span 获取到选中之后的按钮,背景变为绿色。

input:checked + span::after{
  transform: translateX(calc(var(--button-width) - var(--toggle-diameter) - var(--toggle-shadow-offset)));
  box-shadow: calc(var(--toggle-shadow-offset) * -1) 0 calc(var(--toggle-shadow-offset) * 4) rgba(0, 0, 0, 0.1);
}

选中之后处理里面的小圆形,translateX改变位置,box-shadow也把阴影的方向做了改变。

input:active + span::after{
  width: var(--toggle-wider);
}

:active获取长按状态,改变小圆形的宽度。

input:active:checked + span::after{
  transform: translateX(calc(var(--button-width) - var(--toggle-wider) - var(--button-toggle-offset)));
}

:active:checked 获取到选中且在长按下的状态,这个时候需要调整下小圆形的left,达到未选中时长按小圆形往右边变长,选中时长按小圆形往左边变长的效果。 走到这一步基本上iOS风格的switch交互就实现了,可以把input的display设为none来隐藏掉,span和span::after里面都加上 transition: all 0.3s ease-in-out; 来实现平滑的动画效果。

适配dark模式

@media(prefers-color-scheme: dark){
  body{
    background-color: #1c1c1e;
  }
  span{
    background-color: var(--color-dark-grey);
  }
}

@media(prefers-color-scheme: dark)里面的css效果,会在系统设置成dark模式在被启用,整个效果如下图

屏幕录制2023-08-28-16.23.41.gif

本文是一篇记录笔记,视频源:CodingStartUp