用 CSS Filter 反色实现简易黑暗模式

自己博客用的主题不支持黑暗模式,于是改了改别人的代码自己加了一个。用简单 JS+CSS 实现黑暗模式,灵感来源于 Dark Reader。支持

  • 用户有偏好时使用用户偏好,无偏好时检测并使用系统/浏览器级别的黑暗模式设定(CSS Media Query 没有简单的用户 override 方式)
  • 不影响图片、视频
  • 可以方便的设定排除范围(如社交媒体相关图标)

(如有需要可以自己微调文本、链接等颜色)

原始代码来源: Adding dark mode to a Hugo static website without learning CSS | radu’s blog (radu-matei.com)
参考: 几行CSS让整站支持深色模式的探索与拓展 « 张鑫旭-鑫空间-鑫生活 (zhangxinxu.com)

效果
image.png

示例代码(为方便写在一起了,实际使用可以把 CSS / JS 拆开)

<!DOCTYPE html>
<html lang="cmn-Hans">
  <head>
    <meta charset="utf-8">
    <title>Hello!</title>
    <style id="dark-mode-theme" disabled> 
    html {
        background-color: #ebebeb !important;
    }
    
    html {
    filter: invert(1) hue-rotate(.5turn);
    }
    
    img:not(.icon-social),
    video,
    code {
    filter: hue-rotate(180deg) contrast(100%) invert(100%);
    }
    </style>
  </head>
  <body>
    <button id="dark-mode-toggle">to light</button>
    <h1>Hello!</h1>
    <p>Do you like dark mode?</p>
    <img src="https://picsum.photos/200/300"></img>
    <hr>
    <img class="icon-social" src="https://github.com/favicon.ico"></img>
  </body>
  <script>
      var toggle = document.getElementById("dark-mode-toggle");
var darkTheme = document.getElementById("dark-mode-theme");

// probe system default dark mode setting
var systemDefault = null
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
    systemDefault = "dark";
} else {
    systemDefault = "light";
}

// use user preference if possible
var savedTheme = localStorage.getItem("dark-mode-storage") || systemDefault;
setTheme(savedTheme);

toggle.addEventListener("click", () => {
    if (toggle.innerText === "to dark" ) {
        setTheme("dark");
    } else if (toggle.innerText === "to light" ) {
        setTheme("light");
    }

});

function setTheme(mode) {
    localStorage.setItem("dark-mode-storage", mode);

    if (mode === "dark") {
        darkTheme.disabled = false;
        toggle.innerText = "to light";
    } else if (mode === "light") {
        darkTheme.disabled = true;
        toggle.innerText = "to dark";
    }
} 
  </script>
</html>

2 Likes

图片可以通过滤镜再变暗一点儿。 L深色模式如果还显示原本的图片,有可能会被浅色图片亮瞎眼。

1 Like

我当初自写自用的护眼模式油猴脚本就是依靠 CSS Filter 滤镜样式实现的三种模式~

1 Like

圖片可以保持原樣。比如一張美女圖片,如果你把它調暗了,可能就沒那麼美了。

赞!不过我的需求场景稍微有些不一样,作为用户的话可以用各种插件/脚本提升自己的浏览体验,但是作为网站开发者/维护者,就还得考虑不会/不合适使用插件/脚本的场景了,因此才内置了一个简易的黑暗模式实现。

诶,点进去一看又是X.I.U大佬。

我试过很多脚本的深色模式都有个问题,就是载入页面后都会先闪下白再变黑,闪的那下对眼睛刺激更大

这个无解,主要是油猴脚本是在网页开始加载后才会运行,始终会慢一步。
不过我平时用模式 2 的话,影响比较小(模式 3 颜色变化太大比较明显)。

刚刚想到个讨巧的方法,利用“网页加速器”的脚本提前加载好要点击的链接,再点开时就能实现消除“闪白”。不过效果一般般。