data-theme值必须与CSS选择器完全一致,高对比样式需独立于主题且最后加载,焦点指示须用solid outline,CSS变量应分层覆盖避免对比度失效。

data-theme 值不匹配导致 CSS 变量未生效
主题切换后文字变灰、按钮不可见,但控制台没报错——大概率是 data-theme 属性值和 CSS 选择器对不上。比如 JS 设置了 document.documentElement.setAttribute('data-theme', 'dark'),而 CSS 写的是 [data-theme="theme-dark"],两者不一致,浏览器直接跳过该规则块。
- 检查所有
[data-theme="xxx"]选择器中的字符串,必须和 JS 中setAttribute的第二个参数完全一致(大小写、连字符、空格都不能差) - 避免用
"dark"/"light"这类简写,统一用"theme-dark"/"theme-light",降低歧义风险 - 初始化时从
localStorage读取后,要立刻同步到document.documentElement,否则首次渲染会 fallback 到浏览器默认样式,可能触发低对比度
高对比模式下 background-color 被系统强制清空
用户开了 Windows 高对比主题或 macOS 强制色彩,页面按钮突然“消失”——不是 JS 没执行,而是系统把所有 background-color 都干掉了,只保留 color 和 outline。这时如果主题 CSS 把关键对比逻辑全塞在 [data-theme="theme-dark"] 里,高对比规则根本不会触发。
- 高对比样式必须独立于
data-theme,直接写在html或body上,例如:@media (prefers-contrast: high) { html { color: #000 !important; } } - 不要嵌套媒体查询:
[data-theme="theme-dark"] @media (prefers-contrast: high)是无效语法,浏览器直接忽略整条规则 - 确保高对比 CSS 文件或
<style>块在所有主题样式表之后加载,否则前面的background-color: #121212会覆盖掉高对比下的color声明
:focus-outline 在主题切换后失效
键盘 Tab 切换焦点时,焦点框不见了——常见于用 div[role="button"] 替代原生 button,或者主题 CSS 里写了 *:focus { outline: none } 却没补上可访问的替代方案。
- 所有交互控件必须用语义化标签:
button、input、select、label,别用div+role模拟 - 主题 CSS 中禁用 outline 时,必须为每种主题提供等效的焦点指示,例如:
[data-theme="theme-dark"] button:focus { outline: 2px solid #4dabf7; } - 高对比模式下,
outline是唯一可靠焦点提示,不能被border或box-shadow替代;且必须用solid样式,虚线/点线会被系统过滤
字体颜色与背景色的动态对比度崩塌
深色主题下标题看着还行,但切到高对比模式后,标题变成黑底黑字——因为主题变量只定义了 --text 和 --bg,没考虑高对比下系统会重置颜色,导致变量计算链断裂。
立即学习“前端免费学习笔记(深入)”;
- CSS 变量不能只依赖
:root或单层[data-theme],必须配合媒体查询分层覆盖::root { --text: #333; } [data-theme="theme-dark"] { --text: #eee; } @media (prefers-contrast: high) { :root { --text: #000; --bg: #fff; } } - 避免在 JS 中动态计算颜色(如
hexToRgb),高对比模式下 JS 获取的getComputedStyle值不可靠,应全部交由 CSS 媒体查询处理 - 测试时必须手动开启系统级高对比设置(Windows 设置 > 辅助功能 > 高对比度;macOS 系统设置 > 辅助功能 > 显示 > 高对比度),不能只靠 DevTools 的模拟开关



















