HTML无原生护眼模式,需用CSS滤镜实现;推荐sepia(0.7)+hue-rotate(12deg)+brightness(1.05)组合,并配合localStorage存用户选择、@supports检测及合理CSS变量层级。

HTML 本身不提供“护眼模式”开关,所谓护眼效果必须靠 CSS 滤镜或颜色变量主动实现;直接写 color-temperature: 3500K 或 warm-filter() 会完全失效——浏览器根本不认识这些属性。
用 sepia() + hue-rotate() 快速模拟暖色滤镜
这是目前最轻量、兼容性最好的纯 CSS 方案,适合全局页面或图片层级。不要试图用 filter: brightness() contrast() 单独调,容易发灰或刺眼。
-
sepia(0.7)是起点:保留文字可读性,又带明显棕黄基底 - 再叠加
hue-rotate(12deg)微调——正数偏暖(红/黄),负数偏冷(青/蓝) - 加
brightness(1.05)补偿 sepia 带来的轻微压暗,避免整体发闷 - 移动端需包裹在
@supports (filter: sepia(0))里,并配 fallback 背景色(如background-color: #fdf6e3)
用 input[type="range"] 实现色温滑块但不依赖 JS 初始化
滑块本身只是输入控件,value 设为 3500 只是初始值,页面不会自动变暖——必须手动绑定到 CSS 变量或样式上才能生效。
- HTML 中写:
<input type="range" min="2000" max="6500" value="3500" step="100" id="kelvin-slider"> - 配合
aria-valuetext="护眼模式已启用",让屏幕阅读器一进页就感知状态 - 别用
step="500":人眼对色温变化敏感,步进太大(如从 4000K 直跳 4500K)会明显跳变 - 若后续用 JS 更新,首次加载时必须手动触发一次更新函数,否则首屏闪回标准色温
用户手动切换优先级必须高于系统偏好
很多人只监听 prefers-color-scheme,却忽略用户点过“护眼模式”按钮后,刷新页面又回到系统默认——这不是 bug,是逻辑没写全。
立即学习“前端免费学习笔记(深入)”;
- 用
localStorage存用户选择(sessionStorage关页即丢,不合适) - 初始化时顺序必须是:先读
localStorage→ 再 fallback 到window.matchMedia('(prefers-color-scheme: dark)')→ 最后设document.documentElement.classList - 监听系统变化时,不能无条件覆盖:要判断当前是否为用户手动模式,是则跳过
- CSS 变量必须分层定义——基础变量(如
--text-default)放:root,主题变量(如--bg-body)在.theme-warm类里重定义
别碰 filter: invert(1) hue-rotate(180deg) 这类“一键护眼”方案
它确实能快速反色,但副作用太硬:所有图片、图标、视频都会被反转,即使你给 img 单独加 filter: invert(1) 补救,也难保色彩准确,尤其 PNG 透明通道和 JPEG 色深损失会放大失真。
- 该方案无法区分文字、背景、图片的处理需求,属于暴力覆盖
- 在 iOS Safari 和部分安卓 WebView 上,复合 filter 容易被整体忽略或降级
- 真正需要护眼的场景(如长时间阅读),用户更在意自然、稳定、低干扰——不是越“酷”越好
最容易被忽略的一点:CSS 变量名和 class 名的优先级关系。把所有变量都堆在 :root 里,再指望一个 .theme-warm class 覆盖掉它们,大概率失败——必须确保主题 class 的选择器权重 ≥ 变量定义位置,推荐用 html.theme-warm 或 body.theme-warm 开头。



















