用 CSS 变量与 prefers-color-scheme 做一键深色模式:一次学习笔记
最近给自己的小工具页面加深色模式,顺手把做法整理成这篇笔记。目标很简单:亮色和深色只维护一套样式,切换时不改结构、不重写颜色,用户的选择还要能记住,下次打开仍然生效。
一、先把颜色收进 CSS 变量
以前写页面,颜色散落在各个选择器里,改一套主题就要逐行替换。现在的做法是把全部语义颜色集中定义在 :root 里,例如背景、文字、卡片、边框和主色各一个变量,组件只引用变量,不写死色值。切换主题时,只需要换掉这一组变量的值,页面其余样式完全不动,维护成本立刻降下来。
二、用 prefers-color-scheme 跟随系统
浏览器提供了 prefers-color-scheme 媒体查询,可以读到用户系统的亮色或深色偏好。在 CSS 里写一段 @media (prefers-color-scheme: dark),在其中重定义同一组变量,页面第一次打开就能自动贴合系统设置,不用用户先手动点一次。这一步只做默认值,不做强制记忆。
三、手动切换:给 html 加一个属性
自动跟随系统还不够,用户常常想在网页里自己选。做法是在 html 元素上放一个 data-theme 属性,取值为 light 或 dark,CSS 里用 html[data-theme="dark"] 覆盖变量。点击切换按钮时,用 JavaScript 在 light 和 dark 之间翻转这个属性,同时把结果写进 localStorage。下次打开页面,先读 localStorage,有保存值就用保存值,没有才跟随系统。
四、切换时避免闪烁的两个细节
第一个细节是脚本要尽早执行:读取 localStorage 并设置 data-theme 的小段脚本放在 head 里、样式之前执行,避免页面先以亮色闪一下再变深色。第二个细节是给颜色加过渡:对 background-color 和 color 加一个 0.2 秒左右的 transition,切换看起来是平滑渐变,而不是生硬跳变。过渡时间不宜太长,否则每次切换都像在等待。
五、一个最小可用的示例
:root { --bg: #ffffff; --text: #1f2937; --card: #f3f4f6; --accent: #2563eb; }
@media (prefers-color-scheme: dark) { :root { --bg: #111827; --text: #f9fafb; --card: #1f2937; --accent: #60a5fa; } }
html[data-theme="dark"] { --bg: #111827; --text: #f9fafb; --card: #1f2937; --accent: #60a5fa; }
body { background: var(--bg); color: var(--text); }
切换按钮的逻辑只有三行:读当前属性、翻转、保存。localStorage 的键名可以固定,例如 theme。需要注意的是,手动选择应当优先于系统偏好,只有当用户点击“跟随系统”时才清除保存值。
六、学习小结
这次练习的关键收获有三点:第一,颜色要先语义化再谈主题,变量名表达的是用途而不是色值;第二,系统偏好只决定默认值,用户的显式选择永远优先;第三,体验细节决定成败,尽早设置主题和加短过渡,能避免最常见的闪烁问题。下一步想试试把这套变量扩展到图表和代码块配色上,让深色模式覆盖更完整。
以上为个人学习记录,示例代码均为自行编写的最小演示,可直接在空白 HTML 文件中验证。
- 点赞
- 收藏
- 关注作者
评论(0)