这个月 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) 许可协议进行许可,本文的部分内容使用了该文章部分内容且进行了部分修改。