效果演示

文末可一键复制完整代码
源代码
<!DOCTYPE html><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>极简开关</title><style> :root { --sz: 10vmin; --c1: #ffffff; --c2: #848484; --c3: #474747; --c4: #323232; } @property --c2 { syntax: '<color>'; inherits: false; initial-value: #848484; } *, *:before { box-sizing: border-box; transition: all 0.5s ease 0s; } body { margin: 0; padding: 0; width: 100vw; height: 100vh; overflow: hidden; display: flex; align-items: center; justify-content: center; background: var(--c4); } .toggle { position: relative; width: calc(var(--sz) * 4); height: calc(var(--sz) * 2); display: flex; align-items: center; justify-content: center; } input { opacity: 0; visibility: hidden; } label[for=btn] { position: absolute; width: calc(var(--sz) * 4); height: calc(var(--sz) * 2); display: flex; align-items: center; justify-content: center; pointer-events: none; } label[for=btn]:before { content: ""; position: absolute; width: calc(var(--sz) * 3); height: calc(var(--sz) * 0.25); background: var(--c3); border-radius: var(--sz); } .thumb { position: absolute; width: calc(calc(var(--sz) * 2) - calc(var(--sz) / 8)); height: calc(calc(var(--sz) * 2) - calc(var(--sz) / 8)); top: calc(calc( var(--sz) / 10) + calc(var(--sz) / -20)); left: calc(calc( var(--sz) / 10) + calc(var(--sz) / -30)); border-radius: var(--sz); background: var(--c2); cursor: pointer; border: calc(var(--sz) / 4) solid var(--c4); display: flex; align-items: center; justify-content: center; overflow: hidden; pointer-events: all; animation: start-thumb 1.5s ease 0s 1; } .thumb:before { content: ""; position: absolute; width: 65%; height: 65%; background: var(--c4); border-radius: var(--sz); animation: start-thumb-before 1.5s ease 0s 1; } #btn:checked + label .thumb { left: calc(calc(100% - calc(calc(var(--sz) * 2) - calc(var(--sz) / 3))) - calc(calc( var(--sz) / 10) + calc(var(--sz) / 5.75))); --c2: var(--c1); } #btn:checked + label .thumb:before { width: 0%; height: 0%; } @keyframes start-thumb { 0%, 50% { left: calc(calc(100% - calc(calc(var(--sz) * 2) - calc(var(--sz) / 3))) - calc(calc( var(--sz) / 10) + calc(var(--sz) / 5.75))); --c2: var(--c1); } 100% { left: calc(calc( var(--sz) / 10) + calc(var(--sz) / -30)); } } @keyframes start-thumb-before { 0%, 50% { width: 0%; height: 0%; } 100% { width: 65%; height: 65%; } }</style></head><body><divclass="toggle"><inputtype="checkbox"id="btn"><labelfor="btn"><spanclass="thumb"></span></label></div></body></html>实现思路拆分
极简开关是怎么做出来的?
这一篇做一个极简开关:打开页面即可体验核心动效。整页靠 HTML 与 CSS 完成,不用 JavaScript。
整体思路:三块内容分工
可以把成品页面想成三块积木拼在一起:
结构:可点击 label+ 隐藏复选框 + 视觉滑块/字母/图标。布局:Grid 或 Flex 排布轨道与状态符号,尺寸多用 em/clamp缩放。动效:相邻兄弟或 :checked选择器联动transform、opacity,无需 JavaScript。
结构和样式分开写,改灯色或主题色只动 CSS 变量,不动 HTML。
配色与场景氛围
这一版用颜色与背景营造场景,而不只是装饰:
让画面「活」起来
Flex 水平垂直居中排布内容。
动效方面,这一版启用了这些效果:
start-thumb动画循环start-thumb-before动画循环:checked区分两种主状态,无需脚本改 classtransition让状态切换更顺滑
结构拆解:从上到下的图层
可访问的开关骨架
隐藏 checkbox+ 外层label,点击整块区域切换
主要结构与图层
.toggle结构节点隐藏 checkbox,驱动:checked/:has()状态
源码获取

夜雨聆风