FlyingSky
回忆化成一场长的梦。
FlyingSky's Blog

给博客添加 DARK Mode (黑暗模式)

给博客添加 DARK Mode (黑暗模式)

这个月 LinusTechTips 怼出了一期视频专门讲了讲 “DARK Mod” ,确实,夜间刷刷刷的时候还是黑底白字看起来更顺眼一点。这回,我来给博客加上夜间模式~~,加入 Deep♂Dark♂Family~~ (咳咳咳皮了)。

看到右下角的“暗”按钮了吗?点击它,开始你的黑暗之旅吧!

思路

本质上讲,Dark Mode 就是在指定时间段内修改页面配色、图片亮度等,既然是动态修改的,就免不了要用到 JavaScript 了。

样式有三种书写形式,分别为外联 ( 额外的 .css 文件,在 HTML 中使用 <link rel="stylesheet" href="..."> 建立连接 ) 、内联 ( 使用 <style>...</style> 将样式写在 HTML 中 ) 和内嵌 ( 在元素上使用 style="..." ) 。使用 JS 修改样式,就有以下三种方式进行操作:

1.引入一个新的外联 CSS 文件,以覆盖原有样式 ( 不影响原有样式文件、方便维护 ) 。2.在原有 CSS 上追加样式,以 class 名区分 ( 方便 JS 操作,实现优雅、方便维护 ) 。3.直接修改元素的 style 属性,即内嵌样式 ( 不推荐 ) 。

在这里博主选用第二种方法。

实现

使用 JS 控制元素 class

JS 中 Element.classList 的 add() 和 remove() 方法,正好满足我们的需求,且支持绝大多数浏览器支持。但先别急着写,还有一个细节:夜间模式这个状态应被保存下来一直生效,或持续到本次会话 Session 结束,cookie 可以满足我们的要求。

所以事情就很明朗了,编写代码:

function switchDarkMode(){
    var night = document.cookie.replace(/(?:(?:^|.*;\\s*)dark\\s*\\=\\s*([^;]*).*$)|^.*$/, "$1") || '0';
    if (night == '0'){
        document.body.classList.add('dark');
        document.cookie = "dark=1;path=/";
        console.log('Dark mode on');
    }else{
        document.body.classList.remove('dark');
        document.cookie = "dark=0;path=/";
        console.log('Dark mode off');
    }
}

即可实现夜间模式的 切换 和 状态保存 。

在指定时间段内修改

思路很简单,页面加载后判断时间,在指定范围内修改元素 class

(function(){
    if(document.cookie.replace(/(?:(?:^|.*;\\s*)dark\\s*\\=\\s*([^;]*).*$)|^.*$/, "$1") === ''){
        if(new Date().getHours() > 22 || new Date().getHours() < 6){
            document.body.classList.add('dark');
            document.cookie = "dark=1;path=/";
            console.log('Dark mode on');
        }else{
            document.body.classList.remove('dark');
            document.cookie = "dark=0;path=/";
            console.log('Dark mode off');
        }
    }else{
        var dark = document.cookie.replace(/(?:(?:^|.*;\\s*)dark\\s*\\=\\s*([^;]*).*$)|^.*$/, "$1") || '0';
        if(dark == '0'){
            document.body.classList.remove('dark');
        }else if(dark == '1'){
            document.body.classList.add('dark');
        }
    }
})();

具体的样式内容

在上面的代码中,我们控制了 <body> 元素的 class,这是所有页面元素的祖先元素。启用夜间模式时,<body> 的 class 值含有 dark ( 即 <body class="dark"> ) 。因此在编写夜间模式的样式时,在样式选择器前加 body.night 即可,可酌情使用 !important 。

图片亮度

使用 CSS 滤镜中的 brightness() 滤镜 ( 仅支持现代浏览器 ) 可以实现:

body.night img {
    filter: brightness(50%);
}

后端处理

因为是在本地通过 JS 操控样式,所以在 JS 加载前后样式不一样,会导致页面闪烁 然后闪瞎。可在博客主题中加上判断,当检测到 cookie含有相关字段后可直接输出 <body class="dark"> ,如:

<body class="<?php if($_COOKIE['dark']=='1'){echo'dark';} ?>">

加个按钮

这个就随网站样式而定啦,只要在元素上加上 onclick="switchDarkMode()" 就行了。

动态修改按钮内容

你可能注意到了,本站右下角的 Dark Mode 切换按钮上的字是会变的,即在 Dark Mode 开启时显示“亮”,关闭时显示“暗”,其实用 innerHTML 就可以更改啦。这样的话就需要在按钮元素上加个 id="..." ,然后在 JS 上加行代码。

跨域使用

如果您有多个站点都要设置上 Dark Mode ,又不想让用户在切换站点后重新开关 Dark Mode ( 即多站点的 Dark Mode 开关设定统一 ) ,这时,您可以通过设置 Cookie 作用域实现它。

Cookie 可以设置作用路径和作用域,限定 Cookie 的生效范围。目前来说,最大的作用范围就是整个域名 ( 比如 fsky7.com ) ,这样该域名下所有主机的所有位置 ( 比如 blog.fsky7.com 或 board.fsky7.com/ssl ) 都能获取该 Cookie 。

在 JavaScript 里,在 Cookie 内容后面加上 domain=... 即可,比如我们这次实现用到的代码:

document.cookie = "dark=1;path=/;domain=fsky7.com";
...
document.cookie = "dark=0;path=/;domain=fsky7.com";

( 拓展:PHP 中设置 Cookie 的操作是 setcookie(name, value, expire, path, domain); ,可以在最后一个参数里面设置作用域 )

所以,实现这个方法只需要在每个 document.cookie 的值后面加上作用域即可。

如果您使用的是 Initial 主题 可以直接参考 Initial 简约主题的本站食用方式 -> 实用功能 -> 黑暗模式 。

实时更新

使用场景:访问者同时打开了两个分别为不同站点的标签页 ( 比如 https://blog.fsky7.com/archives/46/ 和 https://board.fsky7.com/ssl/ ) ,访问者在其中一个标签页更开关了 Dark Mode ,然后切换到了另一个标签页,这个功能让另一个标签也同步更新 Dark Mode 的开关情况。

实现方式:加一串 JavaScript 代码,使其在切换标签页时进行判断。

document.addEventListener('visibilitychange', function () {
    var dark = document.cookie.replace(/(?:(?:^|.*;\\s*)dark\\s*\\=\\s*([^;]*).*$)|^.*$/, "$1") || '0';
    if(dark == '0'){
        document.body.classList.remove('dark');
        document.getElementById("darkmode").innerHTML="暗";
    }else if(dark == '1'){
        document.body.classList.add('dark');
        document.getElementById("darkmode").innerHTML="亮";
    }
});

给滚动条也适配上

感谢 Nanlon 提出的要求。

这个可以通过 ::-webkit-scrollbar 实现。

::-webkit-scrollbar 仅仅在支持 WebKit 的浏览器 (例如, Chrome, Safari) 中使用

请参见文章:::-webkit-scrollbar。本站的食用方式看下一节。

本站的食用方式

请参见文章:Initial 简约主题的本站食用方式 -> 实用功能 -> 黑暗模式 。

鸣谢

本文参考由 journey.ad 创作的文章 给博客添加夜间模式 – 猫与向日葵 ,原文使用 知识共享署名 4.0 国际 (CC BY 4.0) 许可协议进行许可,本文的部分内容使用了该文章部分内容且进行了部分修改。

FlyingSky's Blog

给博客添加 DARK Mode (黑暗模式)
这个月 LinusTechTips 怼出了一期视频专门讲了讲 "DARK Mod" ,确实,夜间刷刷刷的时候还是黑底白字看起来更顺眼一点。这回,我来给博客加上夜间模式~~,加入 Deep♂Dark♂Family…
扫描二维码继续阅读
2019-01-29