欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

如何将网站调整为暗色模式,并实现手动和自动切换

最编程 2024-03-30 15:13:13
...

文章简介

现在,常见的操作系统,基本都已经适配了暗色/亮色模式,并提供API接口:

  • macOS Mojave 10.14 开始提供了外观设置选项,支持设置 浅色 / 深色 外观。
  • Windows10 1809版开始支持亮色/暗色主题风格。
  • Android 10 (API 级别 29)开始支持深色主题背景(第三方OEM厂商可能有所差异)。
  • iOS13开始全面支持暗色模式。

那么,我们自己的网站如何适配暗色/亮色模式呢?首先说一下最基础的媒体查询,然后带大家了解一下我的适配方案(纯JS、CSS和HTML的前端操作)

效果图
效果图

媒体查询的优缺点

很多文章会介绍你直接使用媒体查询来适配暗色模式;的确高版本的浏览器,可以提供媒体查询功能,使用CSS,加入媒体判断即可:

/\* 常规浅色模式下的网页背景颜色及文本颜色 \*/

body {

 background: #fff;

 color: #222;

}

/\* 深色模式下的网页背景颜色及文本颜色 \*/

@media (prefers-color-scheme: dark) {

 body {

 background-color: #222;

 color: #ddd;

 }

}

prefers-color-scheme支持三个值,分别是 :

  • no-preference:无指定
  • light:亮色
  • dark:暗色

这样的好处是适配快,但是坏处也有,主要的体现是无法用户主动切换

举个例子,有些用户习惯把系统长期设置为暗色模式,访问你网站时,想看清你网站的图片,希望调整成亮色模式,却必须到系统设置内,手动把系统配色调成亮色再刷新网站,体验差

当时还好,我们有JS,使用JS也可以媒体查询,我们就不需要用CSS来媒体查询系统暗色或亮色配色

// JS查询是系统是否为暗色配色

matchMedia('(prefers-color-scheme: dark)').matches

下文,我们开始给网站适配。

适配逻辑

本次适配的适配暗色/亮色模式的用户操作逻辑分两种情况:存在暗色模式标识符不存在暗色模式标识符

暗色标识符:由暗色/亮色按钮调用的JS实现存储在CookieslocalStorage内,用来提示JS展现那种页面配色。

暗色/亮色的现实主要是,当需要给用户展现网站暗色配色时,在HTML内<body>标签内加入class="night"

不存在暗色模式标识符

用户进入网站,若之前没有手动点击网站上切换暗色/亮色按钮(不存在暗色模式标识符),则使用媒体查询检测用户是否有开启暗色模式,同步系统配色。

同时,媒体查询存在一定的兼容性问题,浏览器版本过低(如:IE 9),在查询失败时:

则逻辑判断用户当前系统时间,根据时间显示暗色亮色配色。

存在暗色模式标识符

若用户之前有点击过切换暗色/亮色按钮,查询CookieslocalStorage内暗色模式标识符来展示暗色/亮色配色,优先级高于媒体查询和时间判断

HTML结构

首先,我们依靠<body>标签内是否存在class="night"来实现,所以JS引用,最好紧接<body>标签:

<body>

<!--切换`亮色/暗色`按钮,加上"小埋皮肤"-->

<i onclick="switchNightMode()" id="xm"></i>

<!--`亮色/暗色`逻辑判断JS"-->

<script type="text/javascript" src="/DarkMode/js/switch.js"></script>
<i onclick="switchNightMode()" id="xm"></i>

这条是我实现的切换暗色/亮色按钮,大家可以根据自己需要进行替换:

CSS结构

因为暗色模式的现实是依靠<body>标签内是否存在class="night"来实现:

.night {

 color: #E0E0E0;

 background-color: #424242;

}

派生

因为我们是直接在<body>标签内添加CSS叠加,所以,按照样式的优先级来说,在CSS内使用,我们就需要使用派生方法写样式,如:

/\*暗色模式span标签\*/

.night span {

 color: #E0E0E0;

}

/\*暗色模式警告按钮样式\*/

.night .btn-danger {

 color: #fff;

 background-color: #e45353a1;

 border-color: #e45353a1;

}

以此类推,根据自己亮色模式下的样式,适配暗色模式即可。

图片处理

另外,为了让暗色模式下,图片不要过度亮而刺眼,我们添加filter样式:

.night img{

 filter: brightness(0.9);

}

JS结构

JS结构就比较复杂了,主要分三个部分

进入网站,判断是否启动暗色模式

//检查当前主题模式和系统主题是否对应Start

function checkNightMode() {

 var Mode = document.cookie.split(";")[0].split("=")[1];

 cookiesExp=new Date(new Date().setMonth(new Date().getMonth()+1));

 //存在暗色模式标识符,且Cookies中DarkMode值为1

 if (Mode == 1) {

 // 值为1:添加class="night"到body标签"

 $("body").addClass("night");

 }

 //不存在暗色模式标识符情况下,是否需要启用暗色模式

 else if (Mode == null || Mode == "undefined" || Mode == "") {

 // 媒体查询,用户系统是否启动暗色模式

 if (matchMedia('(prefers-color-scheme: dark)').matches) {

 $("body").addClass("night");

 }

 // 媒体查询,用户系统是否启动亮色模式

 else if (matchMedia('(prefers-color-scheme: light)').matches) {

 $("body").removeClass("night");

 } 

 // 时间判断,是不是到点了( ;´Д`)

 else if (new Date().getHours() >= 21 || new Date().getHours() < 7) {

 $("body").addClass("night");

 }

 }

}

//检查当前主题模式和系统主题是否对应End

这个JS是在用户进入网站,加载到<body>标签时,进行判断,是否需要在表情内加入class="night"。先判断是否有标识符,再判断媒体查询结果,最后判断用户系统时间,优先级逐级递减。

用户主动切换按钮

// 切换暗亮模式Start

function switchNightMode() {

 // 获取Cookies内DarkMode值

 var Mode = document.cookie.split(";")[0].split("=")[1];

 // 如果DarkMode值不存在,也就是不存在标识符

 if (Mode == null || Mode == "undefined" || Mode == "") {

 // 判断是否处于暗色模式

 if ($("body").hasClass("night")) {

 // 处于暗色模式,删除标签内night

 $("body").removeClass("night");

 // 添加标识符

 document.cookie = "DarkMode=0;path=/" + ";expires=" + cookiesExp.toGMTString();

 $('#nightMode').removeClass("icon-yueliang").addClass("icon-zhishifufeiqiapianicon-");

 } else {

 // 不处于暗色模式,添加标签

 $("body").addClass("night");

 // 添加标识符

 document.cookie = "DarkMode=1;path=/" + ";expires=" + cookiesExp.toGMTString();

 $('#nightMode').removeClass("icon-zhishifufeiqiapianicon-").addClass("icon-yueliang");

 }

 } else if (Mode == '0') {

 // 标识符为0,代表之前没开启暗色模式

 $("body").addClass("night");

 document.cookie = "DarkMode=1;path=/" + ";expires=" + cookiesExp.toGMTString();

 $('#nightMode').removeClass("icon-zhishifufeiqiapianicon-").addClass("icon-yueliang");

 } else {

 $("body").removeClass("night");

 document.cookie = "DarkMode=0;path=/" + ";expires=" + cookiesExp.toGMTString();

 $('#nightMode').removeClass("icon-yueliang").addClass("icon-zhishifufeiqiapianicon-");

 }

}

// 切换暗亮模式End

用户主动切换按钮,是在用户点击某个元素,触发onclick函数事件,这边为还替换了页面id为nightMode标签内的图标:

图标替换
图标替换

系统配色切换监听

其实,配置已经基本配置完成,但是如果用户设置的是自动变换配色,如Mac用户的外观自动

在系统自动切换暗色/亮色的同时,如何让网站也一同切换?

答案就是创建监听器:

// 监听暗色、亮色切换Start

let lightMedia = window.matchMedia('(prefers-color-scheme: light)');

let darkMedia = window.matchMedia('(prefers-color-scheme: dark)');

let callback = (e) => {

 let prefersDarkMode = e.matches;

 if (prefersDarkMode) {

 checkNightMode();

 }

};

if (typeof darkMedia.addEventListener === 'function'||typeof lightMedia.addEventListener === 'function') {

 lightMedia.addEventListener('change', callback);

 darkMedia.addEventListener('change', callback);

}

// 监听暗色、亮色切换End

这样就可以在用户系统更改配色的同时,网站随之更改了。

Demo

最后,可以看看我适配好的效果图网站:https://image.mintimate.cn

Tips

本次适配,标识符存储在Cookies内,且设置切换一次后,有效期为30天,实际生产环境中,存储在localStorage内可能是一个更好的选择。

推荐阅读