不能只靠改颜色值增强对比度,必须用lch()或hsl()重算明度并配合color-scheme声明;纯白文字在OLED深色屏上辉光,#e0e0e0实际对比度仅≈3.2:1,低于WCAG AA要求。

直接结论:不能只靠改颜色值来“增强对比度”,必须用感知亮度模型(如 lch() 或 hsl())重算文本与背景的相对明度,并配合 color-scheme 声明触发系统级渲染适配。
为什么改个 #ffffff → #e0e0e0 反而让文字更糊?
纯白文字在 OLED 深色屏上会辉光,边缘发虚;而人眼在暗环境下对中高亮度色敏感度下降,#e0e0e0 实际对比度可能只有 ≈3.2:1,远低于 WCAG AA 要求的 4.5:1。这不是颜色写错了,是亮度感知脱节了。
实操建议:
- 用 Chrome DevTools 的「Accessibility」面板实时测目标元素对比度,别信肉眼
- 避免用十六进制硬调,改用
lch(92% 0 0)(柔和白)配lch(28% 0 0)(非纯黑) - 深色模式下,主文本 L 值建议落在 88%–94%,次要文本 60%–72%,别用
opacity降级
lch() 和 hsl() 在变量里怎么安全使用?
lch() 是目前最接近人眼感知的 CSS 颜色函数,L 通道直连亮度,但兼容性有限;hsl() 更通用,需手动拉高 L 和 S 补偿暗背景衰减。
立即学习“前端免费学习笔记(深入)”;
常见错误现象:写了 hsl(210, 10%, 70%),切暗色后还是看不清——因为 S 太低,L 在暗背景下“塌陷”了。
实操建议:
- 亮色模式定义:
--text-primary: hsl(210, 10%, 20%) - 暗色模式覆盖:
--text-primary: hsl(210, 25%, 85%)(S+15%,L+65%) - 若支持
lch(),优先用:--text-primary: lch(92% 0 210),回退到hsl()用@supports包裹 - 所有变量必须带语义,如
--text-primary,别用--gray-300这类上下文无关名
为什么 @media (prefers-color-scheme: dark) 改了变量,但 input 边框还是亮的?
媒体查询只管你写的 CSS,不管浏览器原生控件。没声明 color-scheme,input、滚动条、button 等仍走系统默认逻辑,你的变量根本没被采纳。
实操建议:
- 必须在
<head>加:<meta name="color-scheme" content="light dark"> - 同时在
:root声明:color-scheme: light dark - 第三方组件(如 MUI)的边框色常漏覆盖,得单独加:
.MuiInputBase-root :is(input, textarea) { border-color: var(--border-color); } - 检查 computed styles,确认
color-scheme显示为light dark,不是normal
gap、border、shadow 的对比度为什么也要重算?
Grid 的 gap 不是“空隙”,是视觉分隔通道;border-color: #333 在 #121212 上差值仅 ~20,人眼几乎分辨不出。这不是 bug,是明暗关系重构失败。
实操建议:
-
gap建议比亮色模式增大 20%–30%,或加内阴影:box-shadow: inset 0 0 0 1px rgba(255,255,255,0.05) -
border-color别用灰阶,改用带色相的lch(45% 12 220)(冷调灰蓝),比纯灰更易识别 -
box-shadow的blur值在暗色下要收窄,spread可微增,避免“发晕”感 - 所有这些变量都必须和文本色同源,比如共用
--brand-h,确保色调统一
最容易被忽略的是:对比度不是单点问题,是整个视觉层级的再平衡。改一个 --text-primary,--border-color、--gap-bg、--shadow-inset 全得跟着重估——否则系统认出你在“假装暗色”。


















