【笔记】web 黑夜模式通用适配方案
Apr 26, 2025笔记css
【笔记】web 黑夜模式通用适配方案
一、判断黑夜模式的方式
1.1 CSS 媒体查询判断黑夜模式的属性——prefers-color-scheme
prefers-color-scheme CSS 媒体特性用于检测用户是否有将系统的主题色设置为亮色或者暗色。 ——MDN
值:
no-preference
:表示系统未得知用户在这方面的选项。在布尔值上下文中,其执行结果为 false。light
:表示用户已告知系统他们选择使用浅色主题的界面。dark
:表示用户已告知系统他们选择使用暗色主题的界面。
如
1 | /* Light mode */ |
1.1.1 兼容情况
除了 IE 外,其他主流浏览器基本都支持prefers-color-scheme
。
1.2 JavaScript 判断黑夜模式的属性——matchMedia
Window 的 matchMedia() 方法返回一个新的 MediaQueryList 对象,表示指定的媒体查询字符串解析后的结果。返回的 MediaQueryList 可被用于判定 Document 是否匹配媒体查询,或者监控一个 document 来判定它匹配了或者停止匹配了此媒体查询。 ——MDN
window.matchMedia(xxx) 返回一个 listenable-like 对象 MediaQueryList
, 它继承自 EventTarget
, 这意味着可以通过直接它获得最新的 MediaQuery
检测情况:
1 | if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { |
1.2.1 监听主题变化
与 CSS 媒体查询不同,matchMedia
我们需要监听主题的变化作出对应处理,如下所示:
1 | const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)'); |
1.2.2 兼容情况
主流浏览器基本都支持matchMedia
。
二、黑夜模式样式适配处理方案
2.1 CSS 纯媒体查询实现
适用场景:需要快速实现、无需用户自定义主题的项目。如
1 | @media (prefers-color-scheme: dark) { |
优缺点分析
优点:
- 零 js 依赖,纯 css 实现
- 系统级实时响应(跟随系统设置即时切换)
- 维护成本最低
缺点:
- 不能保存用户偏好(比如用户想覆盖系统设置)
2.2 CSS 变量 + 媒体查询
适用场景:中大型项目、需要多主题扩展、已使用 CSS 变量的代码库。
如:
1 | :root { |
优缺点分析
优点:
- 集中管理颜色变量
- 方便扩展多主题
- 支持渐进增强
缺点:
- 仍无法保存用户偏好
- 需要统一使用 CSS 变量规范
2.3 js matchMedia 动态切换 + 本地存储
适用场景:需要用户自定义主题的 ToC 产品、重视用户体验的 Web 应用。
如:
1 | <button id="themeToggle">切换主题</button> |
1 | body.light-mode { |
1 | const themeToggle = document.querySelector('#themeToggle'); |
优缺点分析
优点:
- 支持用户偏好保存
- 同时响应系统和手动切换
- 最佳用户体验
缺点:
- 需要维护两套样式,依赖 js 处理。实现复杂度最高
2.4 js matchMedia 动态切换 + CSS-in-JS 运行时方案
适用场景:适合 React 等框架,已使用 CSS-in-JS 方案
如:
1 | // 使用styled-components示例 |
优缺点分析
优点:
- 完美配合组件化开发
- 主题状态可全局管理
- 支持动态主题切换
缺点:
- 强依赖特定框架
- 需要 CSS-in-JS 体系支持
2.5 *CSS 媒体查询 + filter 滤镜处理
适合场景:要求最快上线、或最小改动。本质其实也归属于方案 1(2.1)
如:
1 | /* 整个页面增加滤镜 */ |
滤镜设置解释
整体滤镜处理可以概括为:反色 + 调整色相
invert(1)
:invert()
函数用于反转输入图像中的颜色。参数定义了转换的程度。如果参数是 1(或者 100%),则会完全反转颜色,即每个颜色通道的值都会被替换为其补色。例如:黑色变成白色,白色变为黑色等。- 当使用
invert(1)
时,则表示将图像的颜色彻底反转,即是:黑色变成白色,白色变为黑色。
- 当使用
hue-rotate(180deg)
:hue-rotate()
函数按照给定的角度旋转色彩轮上的颜色,其实就是冲淡颜色。这里的“角度”是指在标准色轮上转动多少度。色轮是一个圆形图表,显示了不同颜色如何根据它们的色调相互关联。- 当使用
hue-rotate(180deg)
时,意味着所有颜色都会在其原始位置基础上沿着色轮顺时针方向移动 180 度。比如红色会变成青色、绿色变成洋红色、蓝色变成黄色等,因为这些是在色轮上相对的颜色。
- 当使用
更多信息可见MDN - invert、MDN - hue-rotate
兼容情况
除 IE 外,主流浏览器基本能支持。
优缺点分析
优点:
- 开发和维护成本都是最低
- 零 js 依赖,纯 css 实现
- 系统级实时响应(跟随系统设置即时切换)
缺点:
- 不能或很难自定义色值
- 不能保存用户偏好(比如用户想覆盖系统设置)
三、黑夜模式色值设计标准
黑夜模式的色值设计和黑夜模式的工程实现没啥关系,属于用户体验保障。
3.1 WCAG 标准
WCAG(Web Content Accessibility Guidelines) 是由 W3C 制定的国际无障碍标准。其中颜色设置也是一项重要标准。
法律意义:WCAG 在美国《ADA 法案》、欧盟《EN 301 549》等法规中被引用
一些具体要求
- 核心要求
元素类型 | 最小对比度 | 例外场景 |
---|---|---|
普通文本(<18pt/24px) | 4.5:1 | 装饰性/禁用状态文本 |
大文本(≥18pt/24px) | 3:1 | 粗体大文本(≥14pt/18.5px 粗体) |
图形控件(图标/按钮) | 3:1 | 纯装饰性图形 |
- 计算公式
使用相对亮度(Luminance)公式:
1 | Contrast Ratio = (L1 + 0.05) / (L2 + 0.05) |
其中:
- L1 = 较亮颜色的相对亮度(0~1)
- L2 = 较暗颜色的相对亮度(0~1)
实际开发中的应用
- 颜色选择示例
场景 | 通过示例 | 失败示例 |
---|---|---|
白底黑字 | #FFFFFF vs #000000 (21:1) | #FFFFFF vs #666666 (5.74:1) |
深色模式 | #1A1A1A vs #E0E0E0 (10.3:1) | #333333 vs #999999 (3.31:1) |
- 调试工具
自动检测:
1 | # Chrome DevTools |
在线工具:
- 设计技巧
1 | /* 安全配色方案示例 */ |
深度注意事项
- 动态场景:
- 悬停/聚焦状态的对比度需保持合规
- 渐变/阴影覆盖区域需取最差值验证
- 字体特性:
- 300 以下字重需提高对比度要求
- 衬线字体可能需要额外对比度补偿
- 环境适配:
- 移动设备户外模式需考虑屏幕反光影响
- OLED 屏幕需验证 PWM 调光下的可读性
法律合规案例
- Target 诉讼案(2006):因对比度不足赔偿$6 百万
- Domino’s 披萨案(2019):网站对比度违规败诉
- 英国政府:强制要求所有公共网站通过 AA 认证
进阶建议
1.AAA 级目标:
- 普通文本:7:1
- 大文本:4.5:1
- 无障碍测试:
1 | # 使用屏幕阅读器验证 |
设计系统集成:
1 | // Storybook等工具集成对比度检测 |
通过严格遵循这些标准,可确保您的深色模式既美观又合规。建议将对比度检测纳入 CI/CD 流程,实现自动化保障。
Author
My name is Micheal Wayne and this is my blog.
I am a front-end software engineer.
Contact: michealwayne@163.com