现在,常见的操作系统,基本都已经适配了暗色/亮色
模式,并提供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
实现存储在Cookies
或localStorage
内,用来提示JS
展现那种页面配色。
而暗色/亮色的现实主要是,当需要给用户展现网站暗色配色时,在HTML内<body>
标签内加入class="night"
。
用户进入网站,若之前没有手动点击网站上切换暗色/亮色按钮(不存在暗色模式标识符),则使用媒体查询检测用户是否有开启暗色模式,同步系统配色。
同时,媒体查询存在一定的兼容性问题,浏览器版本过低(如:IE 9),在查询失败时:
则逻辑判断用户当前系统时间,根据时间显示暗色或亮色配色。
若用户之前有点击过切换暗色/亮色按钮,查询Cookies
或localStorage
内暗色模式标识符来展示暗色/亮色配色,优先级高于媒体查询和时间判断。
首先,我们依靠<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>
这条是我实现的切换暗色/亮色按钮,大家可以根据自己需要进行替换:
因为暗色模式的现实是依靠<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
结构就比较复杂了,主要分三个部分
//检查当前主题模式和系统主题是否对应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
这样就可以在用户系统更改配色的同时,网站随之更改了。
最后,可以看看我适配好的效果图网站:https://image.mintimate.cn
本次适配,标识符存储在Cookies
内,且设置切换一次后,有效期为30天,实际生产环境中,存储在localStorage
内可能是一个更好的选择。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。