乐于分享
好东西不私藏

明暗切换(可复制源代码)

明暗切换(可复制源代码)

效果演示

文末可一键复制完整代码

源代码

<!DOCTYPE html><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>明暗切换</title><style>@import url('https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap'); * { box-sizing: border-box; } html { font-size: calc(100vmax / 1600 * 100); } @media (max-width:992px) { html { font-size: 100px; } } body { min-height: 100vh; padding: 0.2rem0.5rem; font-size: 0.3rem; display: flex; justify-content: center; align-items: center; background-image: linear-gradient(to right, #ffd65b 50%, #26365150%); background-repeat: no-repeat; background-size: 200%100%; background-position: 00; transition: background-position 0.3s; } body:has(input#dark:checked) { background-position: 100%0; } body:has(input#dark:checked).dot { left: 0.1rem; background-color: #333; } body:has(input#dark:checked).night { top: 50%; } body:has(input#dark:checked).day { top: 150%; } input { display: none; } .btn { display: block; width: 1.6rem; height: 0.7rem; padding: 0.1rem0.2rem; border-radius: 1rem; box-shadow: 2px2px10px#0005; background-color: #fff; font-family: 'Noto Color Emoji', sans-serif; position: relative; overflow: hidden; cursor: pointer; } .dot { position: absolute; width: 0.55rem; height: 0.55rem; top: 50%; left: calc(100% - 0.55rem - 0.1rem); transform: translateY(-50%); border-radius: 50%; background-color: #ddd; transition: all 0.3s; } .day, .night { position: absolute; transform: translateY(-50%); width: 0.55rem; height: 0.55rem; display: flex; justify-content: center; align-items: center; transition: all 0.3s; } .day { left: 0.1rem; top: 50%; } .night { right: 0.1rem; top: 150%; }</style></head><body><divclass="wrapper"><inputtype="checkbox"id="dark"checked><labelclass="btn"for="dark"><divclass="dot"></div><divclass="day">☀️</div><divclass="night">🌛</div></label></div></body></html>

实现思路拆分

明暗切换是怎么画出来的?

明暗切换(light/dark toggle button with css :has())用隐藏 checkbox + body:has(:checked) 切换全页昼夜背景,开关内滑块与 ☀️/🌛 emoji 同步滑动,纯 CSS 无 JS。

说白了就三件事

  1. HTML:input#dark + label.btn,内含 .dot 滑块与 .day / .night emoji。
  2. CSS:body 200% 宽渐变背景,background-position 切换黄/蓝;:has(#dark:checked) 驱动 dot 位置与 emoji 上下滑入。
  3. JavaScript:无。

改尺寸动 $dot-size 等效 rem 值,改过渡动 0.3s,改配色动渐变两色 #ffd65b / #263651。

颜色为啥长这样

  • 日间:暖黄 #ffd65b 占半屏
  • 夜间:深蓝 #263651 占半屏
  • 开关:白底圆角 pill + 浅灰/深灰 dot
  • emoji:Noto Color Emoji ☀️ / 🌛
  • 整体对比鲜明、切换一目了然

动起来是啥感觉

默认 checked(夜间),点击切换昼夜。

  • 未 checked:背景偏黄,dot 在右,☀️ 居中可见,🌛 在下方隐藏
  • checked:背景滑至深蓝,dot 滑左变 #333,🌛 升上,☀️ 下沉隐藏
  • body 背景与开关内动画同步 0.3s
  • pill 阴影 #0005 微浮起

怎么一层层画出来

body 背景切换
  1. linear-gradient(to right, #ffd65b 50%, #263651 50%) 左右各半。
  2. background-size: 200% + background-position 0 或 100% 露出对应半色。
  3. body:has(input#dark:checked) 切 position,无需 class toggle。
开关内部
  1. .dot 绝对定位,left 在右/左两端切换。
  2. .day / .night 用 top: 50% vs 150% 做垂直滑入滑出。
  3. .btnoverflow: hidden 裁剪 emoji 出入动画。

源码获取