暗黑模式切换开关是网页上少数「用户会主动去找」的控件。找不到会被吐槽,找到了按一下没反应更会被吐槽。
而决定按下去那一刻好不好的,不是开关长什么样,是开关点下去以后的四件事。
第一次进站听谁的。用户系统里已经开了深色,你的网站默认还是白的,第一眼就是一片闪光。
prefers-color-scheme这个媒体查询就是为这件事存在的,它应该是默认值,而不是开关按下去才生效的东西。刷新会不会闪一下白。选择存进
localStorage,读取却写在页面底部的脚本里——浏览器会先按 CSS 画一遍浅色,再被 JS 改成深色,用户看到的就是一记白闪。判断和写 class 这一步必须放在<head>里、任何渲染之前。浏览器自己画的那些东西跟不跟着变。输入框、下拉箭头、滚动条、拼写检查的红波浪线,这些不归你的 CSS 管。按 MDN 的
color-scheme文档,这个属性影响的正是「画布表面的颜色、滚动条及其他交互 UI 的默认颜色、表单控件的默认颜色,以及浏览器提供的其他 UI,比如拼写检查的下划线」。所以:root { color-scheme: light dark; }这一行不是可选项。上面那个白闪,还有一半答案在同一个地方。MDN 建议在
<head>里、所有样式之前加上<meta name="color-scheme" content="light dark">,用途写得很直白:「帮助避免页面加载过程中不必要的屏幕闪烁」。一行 meta,比写脚本还早生效。要不要 JavaScript。纯 CSS 方案确实存在(下面就有一款用
:has()做的),但它有个躲不开的边界:状态活在 DOM 里,跳到下一页就没了。想让用户的选择跨页面保留,还是得有一行 JS 去写存储。
(列出来是五条,因为第二件事的答案被拆在了两处:一处在 <head> 的脚本里,一处在那行 meta 上。)
下面十七款按「点下去之后画面怎么变」排:有的只有图标在原地变,有的换了个完全不同的隐喻,有的整块屏幕在转场,还有的根本不是拿来就能装。
一、只有图标在变
最克制的一类:按钮本身在原位,太阳变月亮,页面配色跟着换。它们适合放进已有的导航栏右上角,不会跟现有设计打架。
01. 太阳月亮切换按钮,最标准的那一款
纯 CSS,很轻,亮色下显示小太阳,深色下换成月亮。没有多余动作。
它是这篇的基准线:要的只是一个能用、不出错、别人一眼认得出的开关,它就够了。后面十六款都是在这个基础上加东西,加的每一样都有对应的代价,往下看的时候可以拿它当参照。
02. 太阳飘云,月亮飘星
同样是太阳月亮,但按钮内部是一小块天空:亮色模式下按钮是太阳、背景有白云飘过,深色模式下变成月亮、背景换成流动的星星。纯 CSS。
云和星星是一直在动的,这是它比上一款「贵」的地方——不是性能上的贵,是注意力上的贵。阅读页、文档站这种用户一待十几分钟的地方,视野边缘常年有东西在飘,确实有人会烦。
03. 用 :has() 做到完全不写 JavaScript
这一款值得单独讲。它不靠 JS 给 <html> 加 class,而是用 CSS 的 :has() 选择器,让「某个复选框被勾上」这件事直接反向影响整页的配色,SVG 画的太阳月亮图标也跟着换。
可用性上没什么好担心的:caniuse 上 :has() 的全球支持率 94.82%,Chrome 105、Safari 15.4、Firefox 121 以后都支持。真正的边界是前面说过的那条——纯 CSS 方案记不住用户的选择,翻到下一页就复位了。所以它适合单页站、落地页、作品集这类「就这一页」的场合;内容站还是要加那一行存储。
04. 手柄会滚、图标会转
极简造型,手柄不是滑过去而是滚过去,SVG 的太阳月亮跟着旋转,手柄和图标之间还做了类似混合模式的处理。滚动和背景变化都是纯 CSS。
细节比看上去多,但视觉上收得很紧。这一组里它是最不抢戏的一款。
05. 浮雕质感的凹槽开关
背景做成凹陷的纹理,按钮像被雕在上面,两端分别是太阳和月亮图标,切换时整体配色一起变亮变暗。纯 CSS。
它是这一组里唯一带明确「材质感」的一款。如果你的网站整体走的是新拟态(Neumorphism,用同色系的双向阴影把控件做出从背景里凸出或凹进去的样子)或者别的厚重质感路线,前面几款扁平开关摆上去会像贴纸。
二、换一个隐喻:不是太阳月亮,是灯
太阳月亮讲的是「白天和夜晚」,灯讲的是「开和关」。后者的好处是动作和结果的对应更直接——谁都知道拉一下绳子灯就灭了。这一组适合调性更轻松、或者有文化元素的站点。
06. SVG 灯泡,点一下灭一下
灯泡是 SVG 画的,点击时灯丝明灭,整页主题跟着切换,造型干净没有多余装饰。
它和这一组第 08 款那个灯泡的区别在底层:这一款是自绘的交互元素,那一款的底子是原生复选框。要键盘和读屏也能用,看 08;只想要一个好看的灯泡,这一款更简单。
07. 拉一下绳子
一根垂下来的拉线,拉一下换一次主题,只用 HTML 和 CSS。
拉线这个交互有个现实问题要提前想清楚:它天然要占一段垂直空间,而且位置通常在页面边缘。桌面端很有味道,移动端窄屏上容易和其他元素撞在一起,上线前在手机上多看两眼。
08. 做成复选框的电灯泡
它的底子是一个真的 checkbox,只是被 CSS3 画成了电灯泡。这一点比外观重要:底层还是原生表单控件,键盘的 Tab 和空格键照常能用,读屏软件也认得出这是个可勾选项。
做主题切换时这个优势很实在——很多自绘开关是用 div 拼的,看着好看,键盘用户根本按不到。
09. 灯笼
换成灯笼,靠动态阴影和颜色过渡模拟光线变化。库里绝大多数主题开关是西式的太阳月亮,这一款是少见的中式物件。
用途窄,但窄得很明确:文化类站点、节日专题页、做传统题材内容的博客。
三、整块屏幕在转场
前面两组是按钮在动,这一组是页面在动:幕布拉过、圆形扩散、涂料漫开、立体翻转。
先说一条实际的:用户在你的站上切换主题的次数通常是一次,最多两次,所以这个动画不会被反复欣赏,但一定会被完整看完一次。时长控制在 300 毫秒上下最稳妥——再长,第一次就变成了等待。这一组也是最容易撞上开头第二件事的地方:转场做得越重,刷新时那记白闪越显眼。
10. 图标变形加反转幕布
太阳平滑变形成月亮(是变形,不是换图),同时整页配色随一道反转幕布扫过而翻面。纯 CSS。
它是「图标组」和「转场组」之间的过渡款:转场有,但不夸张,日常网站用得起。
11. 从按钮位置向外扩开的圆
点下去,深色从按钮那一点像水波一样圆形扩散到整屏。用的是 mix-blend-mode(让一个元素和它下面的内容按指定规则混色,而不是简单盖住)加 transition,不依赖任何第三方脚本,颜色可自定义。
顺带说一句现在的另一条路:同样的圆形扩散效果,View Transitions API(全球支持率 91.75%,Chrome 111、Safari 18、Firefox 144 起)也能做,而且能跨 DOM 状态。但它对不支持的浏览器要写降级,而这一款的老办法在哪儿都一样。要求不高的话,老办法反而省事。
12. 像涂料一样漫过去
同样基于 mix-blend-mode,但形状不是规整的圆,而是涂料溢出、元素之间自然融合的那种边缘。完全靠 CSS,不用 JS。
和上一款选哪个,看你的站是理性还是感性:圆形扩散干净利落,涂料漫开更有手感。
13. 立体旋转转场
这一组里唯一明确用 JS 控制切换事件的:布局是 CSS,按钮是 SVG,切换时页面像被立体翻转过去。颜色和转场效果都可以定制,整体仍然轻量。
它的好处恰恰在那行 JS——切换逻辑已经在脚本里,接上 localStorage 和 prefers-color-scheme 是顺手的事,不用像纯 CSS 方案那样再重构一遍结构。
四、不是拿来就能装的几款
前面十三款都是「一个开关,找个地方放上去」。这一组有额外前提:要么它本身是一整块界面、主题切换只是其中一项能力,要么它对周围环境有要求,摆错地方效果就没了。
14. 液态玻璃风格的切换按钮
严格说它还是一个开关,但风格属于另一个体系:半透明玻璃质感,切换时像液体在流动,靠渐变、阴影和透明度堆出来,纯 CSS。
它的前提就是那层背景:玻璃是透的,透出来的是什么决定了它好不好看。放在纯色的后台顶栏上,质感消失大半,看上去就是个灰扑扑的圆角条;放在有图片或渐变背景的品牌页上才成立。
15. 带明暗切换的侧边栏
一整套可展开收起的侧边导航,明暗两套配色都适配好了,HTML+CSS+JS。
后台系统做深色模式,难的从来不是那个开关,是导航、表格、表单、图表每一处都得有第二套颜色,漏一处就是一块刺眼的白。这一款把导航这块交付完整了,往下铺的时候照着它已有的变量命名继续就行,不用另起一套。
16. 把暗色模式做进商品卡本身
左图右文的商品卡,暖米色配金棕,移动端自动变成上下布局。图片区下方内置一个日夜拨动开关,切过去卡片里的场景光线跟着变,完全不用 JS。
这个思路和其他十六款都不一样:主题切换不作用于整页,只作用于这一张卡。电商详情页里展示「同一件商品在白天和夜里」——灯具、窗帘、香薰、睡衣这类——它比整站换肤合适得多。
17. 不止明暗,还有一排颜色可选
明暗之外再给一排主题色,选中的颜色覆盖整页。JS 加 CSS。
它解决的是另一类需求:给用户一个「个性化」的口子。要做这件事,颜色最好只影响强调色(按钮、链接、高亮),别让它同时决定正文和背景——用户挑到一个亮黄,正文对比度就塌了。这一款的变量结构拆得比较清楚,照着改风险小。
看花眼了就按这个顺序来:先打开第 01 款,确认基准线长什么样;想要点性格,在第一组里往下翻;整站想做出记忆点,去第三组;正在做的是后台、商品页这种成块的界面,直接跳第四组,别单独找开关。
选定之后,上线前把开头那几件事倒过来验一遍:把系统调成深色、清掉站点存储、重新打开首页——第一眼是深色的,第一件事过了;按一下开关再刷新,没有白闪,第二件事过了;随便点开一个带输入框的表单,看光标所在的输入框底色和滚动条有没有跟着变深,第三件事过了。三步都过,这个开关才算装好。
以上十七款都可以在童哲网前端特效资源里打开预览。不想自己接线、想直接要一套生来就是深色的站点,看14 款深色模式与暗黑风格网站模板那篇,里面分了原生深色、深浅双主题和可选深色版三种;开关本身的做法还想多看几种形态,14 款 CSS 按钮与开关交互效果里有拟物按压和 Goo 液态形变这些路子;第 15 款那种侧边栏的同类,在11 款导航栏与菜单效果和14 款后台管理系统模板里都还有。


























