03月24, 2022

如何在网页上低成本实现一个简单的“护眼模式”

先看个效果

默认模式:

alt

护眼模式:

alt

对于需要长时间盯着屏幕同学,后面这个“护眼模式”相对“默认模式”的亮底,应该算是更舒适、不那么容易引起视觉疲劳的一个选择。

在当下,作为Web前端开发者,要在网页上添加这么个护眼模式,其实可能并不需要定制化的去针对暗色调写一套完整皮肤样式。

最简单的护眼实现代码

要在任意网站启用上图的“护眼模式”,其实你只需要打开浏览器控制台,执行以下代码就可以了:

    const cssEl = document.createElement('style')
    cssEl.innerHTML = `
        html.cye-enabled {
          filter: contrast(0.96) brightness(0.9) invert(1);
        }
        html.cye-enabled img {
          filter: brightness(0.9) invert(1);
        }
    `;
    document.head.appendChild(cssEl);
    document.documentElement.classList.add('cye-enabled');

很简单对不对。

其实就是给 documentElement 添加一个样式类,相应的,也就是添加个反色滤镜(让亮色变成暗色)。

不想让img图片变成反色而导致肉眼无法识别,则可以再通过滤镜反转回来。

让是否开启“护眼模式”可控

配合离线存储,记住用户设置

支持微调亮度对比度(修改文档流上下文的CSS规则)

如何监听系统主题色调变化

不带UI的,“完整”效果代码

可以复制以下代码到浏览器控制台执行,然后通过 window.setCyeFilter(enabled, contrast, brightness)设置护眼模式开关方式、对比度、亮度。

(() => {
    const cssEl = document.createElement('style')
    cssEl.innerHTML = `
        html.cye-enabled {
          background: #fff; /* 如果有自己的背景色,那么去掉这行 */
          filter: contrast(0.96) brightness(0.9) invert(1);
        }
        html.cye-enabled img {
          filter: brightness(0.9) invert(1);
        }
        html.cye-enabled body {
            filter: none !important; /* 防止三方浏览器插件等重复的护眼样式生效 */
        }
    `;
    document.head.appendChild(cssEl);
    // document.documentElement.classList.add('cye-enabled');

    /***** 一些JS设置逻辑 ****/
    // 护眼模式
    const getLV = (k) => JSON.parse(localStorage.getItem(k));
    const setLV = (k, v) => localStorage.setItem(k, JSON.stringify(v));

    let cyeMediaQueryList = null;
    try {
      cyeMediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');
      cyeMediaQueryList.addListener(setDocCyeByLS); // 通过浏览器API监听系统层面的主题模式配置变换
    } catch(e) {
      console.warn('当前环境可能不支持 matchMedia');
    }
    window.setCyeFilter = (enabled, contrast, brightness) => {
      setLV('cyeEnabled', enabled); // true 开启护眼模式,false 关闭护眼模式,2 跟随系统主题是否黑暗模式动态设定
      setLV('cyeContrast', contrast); // 对比度,可微调视觉效果
      setLV('cyeBrightness', brightness); // 亮度,可微调视觉效果

      // 护眼模式为“开启”或“跟随系统”且系统是开启的
      const isOpen = enabled === true || (enabled == 2 && cyeMediaQueryList && cyeMediaQueryList.matches);
      const { classList } = document.documentElement || {};
      classList && classList[isOpen ? 'add' : 'remove']('cye-enabled');

      if (!isOpen) return;
      const sss = document.styleSheets;
      if (!sss) return;
      let csss = null;
      for (let i = 0; i < sss.length; i++) {
        const cssi = sss[i];
        if (cssi && cssi.ownerNode && cssi.ownerNode.id == 'ghdef') {
          csss = cssi;
          break;
        }
      }
      if (!csss) return;
      const ruls = csss.rules;
      if (!ruls) return;
      let clsObj = null;
      for (let j = 0; j < ruls.length; j++) {
        const rulj = ruls[j];
        if (rulj && rulj.selectorText === 'html.cye-enabled') {
          clsObj = rulj;
          break;
        }
      }
      if (!clsObj) return;
      clsObj.style.filter = 'contrast(' + contrast + ') brightness(' + brightness + ') invert(1)';
      return true;
    };
    // 根据本地存储,判断是否开启护眼模式
    function setDocCyeByLS() {
      setCyeFilter(
        getLV('cyeEnabled'),
        getLV('cyeContrast') || 0.96,
        getLV('cyeBrightness') || 0.9
      );
    };
    setDocCyeByLS();
})()

CSS中的其他可用方案

mix-blend-mode: difference

https://blog.csdn.net/weixin_44733660/article/details/121958062

本文链接:http://blog.pyzy.net/post/cye-enabled.html

-- EOF --

Comments

可以发邮件 huzunjie@pyzy.net 或移步到 https://github.com/huzunjie/blog.pyzy.net/issues 评论交流。