主题切换开关(明暗模式切换器动效源码)

CSSJS 许可:自研原创

主题切换开关源码:一键在明暗主题间平滑过渡,日/月图标旋转交叉切换,圆钮弹性滑动,整个面板配色用 CSS 变量驱动,原生 JS 零依赖可直接接入项目。

效果演示(真实可交互)

暗黑模式已经是现代网站的标配,而「切换的过程」同样是体验的一部分。演示区模拟了一个迷你控制台面板:右上角是明暗切换开关,点击后圆钮弹性滑到对侧,轨道从暖黄渐变切换为深蓝,圆钮里的太阳与月亮图标交叉旋转淡入淡出;同时整个面板的背景、卡片、文字颜色全部通过 CSS 变量平滑过渡到暗色,两张数据卡片同步换肤。再次点击即可切回明亮主题。所有颜色都定义在 --bg、--card、--text 等变量里,接入真实项目时只需把变量的取值换成你自己的设计令牌。切换过程整体约 0.45 秒,视觉上先看到圆钮滑动与图标交叉,再看到整块面板的颜色渐次过渡,层次分明不抢戏。面板内的数据卡片、标题、辅助文字全部跟随变量换肤,不需要改任何子组件样式。明暗主题的变量还可以继续拆分出圆角、阴影等设计令牌,统一管理后整套 UI 的视觉一致性会显著提升,后续改版换主题时也只需改一处定义。

粤喵控制台

主题切换开关 · 明暗即时生效

月度访问量 28.6 万 ↑ 12%
组件下载量 9,432 次

点击右上角开关,整个面板在明暗主题间平滑过渡

完整代码

HTML:面板根节点用 data-theme 标记当前主题,开关是带 role="switch" 的按钮:

<div class="sw-panel" id="swPanel" data-theme="light">
  <header class="sw-head">
    <div>
      <h3>粤喵控制台</h3>
      <p>主题切换开关 · 明暗即时生效</p>
    </div>
    <button class="sw-toggle" id="swToggle" type="button" role="switch" aria-checked="false">
      <span class="sw-knob">
        <svg class="sw-sun"><!-- 太阳图标 --></svg>
        <svg class="sw-moon"><!-- 月亮图标 --></svg>
      </span>
    </button>
  </header>
  <!-- 面板内容卡片 -->
</div>

CSS 核心:主题差异全部收敛在变量层,换肤只改一组值:

.sw-panel {
  --bg: #ffffff; --card: #f3f5fb; --text: #26305c; --sub: #8892ab; --line: #e2e7f6;
  background: var(--bg); color: var(--text);
  transition: background .45s ease, color .45s ease, border-color .45s ease;
}
.sw-panel[data-theme="dark"] {
  --bg: #161c33; --card: #212a4d; --text: #e8ecff; --sub: #8b95c4; --line: #2c3560;
}
/* 所有子元素引用变量,因此无需单独写暗色规则 */
.sw-card { background: var(--card); border: 1px solid var(--line); }

开关圆钮:弹性滑动 + 日月图标交叉旋转:

.sw-knob {
  position: absolute; left: 3px; width: 28px; height: 28px; border-radius: 50%; background: #fff;
  transition: transform .45s cubic-bezier(.34, 1.56, .64, 1);
}
.sw-panel[data-theme="dark"] .sw-knob { transform: translateX(30px); }

.sw-knob svg { grid-area: 1 / 1; transition: opacity .3s ease, transform .4s cubic-bezier(.34,1.56,.64,1); }
.sw-moon { opacity: 0; transform: rotate(120deg) scale(.3); }
.sw-panel[data-theme="dark"] .sw-sun { opacity: 0; transform: rotate(-120deg) scale(.3); }
.sw-panel[data-theme="dark"] .sw-moon { opacity: 1; transform: rotate(0) scale(1); }

原生 JS 只需切换一个属性:

const panel = document.getElementById('swPanel');
const toggle = document.getElementById('swToggle');
toggle.addEventListener('click', () => {
  const dark = panel.dataset.theme === 'dark';
  panel.dataset.theme = dark ? 'light' : 'dark';
  toggle.setAttribute('aria-checked', String(!dark));
});

参数说明

参数默认值说明
主题标记`data-theme=“lightdark”`
变量集--bg/--card/--text/--sub/--line颜色令牌,接入项目时替换成设计系统变量
换肤时长transition: background .45s300-600ms 最自然,过慢会显得拖沓
圆钮行程translateX(30px)需等于轨道宽 - 圆钮宽 - 两侧留白
图标动画rotate + scale + opacity太阳/月亮交叉切换,过冲缓动更有弹性

兼容性与性能

常见问题

Q: 怎么把开关接入全站暗黑模式? 把 data-theme 挂到 <html> 上,变量从 .sw-panel 移到 :root,再把其它组件的颜色全部改成 var(--xxx) 引用,一次切换全站换肤。

Q: 刷新后主题会丢失? 需要持久化:点击时用 localStorage.setItem('theme', ...) 存储,页面加载时读取并提前设置 data-theme,避免闪烁。

Q: 圆钮滑动不到头? 行程 translateX(30px) 必须等于「轨道宽 64 - 圆钮宽 28 - 左右内边距 6 = 30px」,改尺寸时同步换算。

Q: 可以商用吗? 可以。本组件为粤喵自研原创代码,免费商用无需署名。

许可与来源

  • 许可证:自研原创 —— 粤喵自研原创,可免费用于个人与商业项目,无需署名。查看来源公示与许可清单
  • 来源:粤喵团队原创自研(从效果思路到代码实现均为独立完成,未直接复制第三方代码)
  • 首次发布:2026-09-01 · 最近更新:2026-09-01
  • 修改日志:2026-09-01 首次发布;2026-09-13 补充许可证与来源标注、复制按钮说明与法务页入口
  • 纠错:联系页面 / min@cactus.asia,2 个工作日内核实处理

常见问题

这个组件可以商用吗?

可以。本组件为粤喵自研原创,可免费用于个人和商业项目,无需署名。

浏览器兼容性如何?

支持所有现代浏览器(Chrome / Firefox / Safari / Edge 最新版本)。旧版 IE 不支持 CSS 动画相关特性。

怎么修改动画参数?

直接调整 CSS 中的 animation-duration(时长)、animation-timing-function(缓动曲线)等属性即可,代码中有注释说明。

✍️ 作者与审核