我的网站早在 2018 年就实现了浅色和深色主题的切换,但是一直没有写过文章来阐述一下主流的实现方法,今天来就介绍一下各种深色主题实现的方法。

1.深色样式

想要实现网站主题的切换,一般有以下几种思路:

1.1 方法一:使用两个 css 文件

这种方法适用于网站主题样式变化较大的情况,为了便于维护样式文件分开成如 app.css 和 app-dark.css 这样的独立样式文件,然后通过 js 进行样式切换。这种方法的缺点也很明显,多加载了一个文件且切换时会有明显的样式变化,需要用样式过渡进行化解,例如 Mazer 项目就是这样实现的。

1.2 方法二:使用 Dark 属性覆盖

可以将浅色模式样式作为网站的默认样式,所有的深色样式都用 dark 属性:

.box {
    background-color: #fff;
    color: #000;
}

.box.dark {
    background-color: #000;
    color: #fff;
}

只需在样式后面注入 dark 属性就行了:

<div class="box">浅色主题</div>

<div class="box dark">深色主题</div>

这种切换方式不会出现某时刻丢失样式文件的问题,但是你需要指定哪些元素标签需要插入 dark 属性,然后遍历插入。

1.3 方法三:使用颜色注入

还可在 css 样式文件中不要指定颜色,用变量 var(--color) 等进行代替,然后再 :root 中单独指定变量的值,通过 js 注入对应的 root 到页面中:

/* 浅色 */
:root {
    --color-primary: #4154f1;
    --form-color: #fff;
    --color-nav-text-active: rgba(0, 98, 182, 1);
    --color-nav-text: rgba(0, 98, 182, 0.6);
    --icon-color: rgba(1, 41, 112, 0.5);
    --main-theme-color: #012970;
    --main-text-color: #444444;
    --box-shadow: 0 16px 56px #e7ebf6AA;
}

/* 深色 */
:root {
    --color-primary: #0062b6;
    --form-color: #fffefe;
    --color-nav-text-active: rgba(255, 255, 255, 1);
    --color-nav-text: rgba(255, 255, 255, 0.6);
    --icon-color: rgba(166, 180, 204, 0.9);
    --main-theme-color: #b5def9;
    --main-text-color: #efefef;
    --box-shadow: 0 16px 56px #000000AA;
}

我的网站就是使用这种方法,因为这样可以让 :root 最先加载,不会出现 loading 加载样式慢的问题。

1.4 方法四:color-scheme

您可以更改在 :root 上设置的 color-scheme 的值,并查看网页如何响应:

  • 设置为 light dark 时,表示相应元素同时支持浅色模式和深色模式。具体选择使用哪种值,取决于 prefers-color-scheme 媒体条件的值
  • 设置为 light 时,表示该元素支持浅色配色方案
  • 设置为 dark 时,表示此元素支持深色配色方案

See the Pen color-scheme: light dark; and System Colors by web.dev (@web-dot-dev) on CodePen.

2.样式切换判断

已经实现了深色主题的样式,那么什么事情情况下进行切换呢,一般有如下几种常用方案:

  • 读取用户当地时间,每天设置固定时间例如:19:00 至次日 6:00 自动开启主题切换
  • 读取用户当地日落日出时间,自动进行设置
  • 读取用户系统主题颜色,根据系统颜色进行切换

2.1 通过 css 媒体查询

在 CSS 中可以使用利用媒体属性 preferred-color-scheme 查询:

@media (prefers-color-scheme: light) { 
  .article {  
    background:#fff; 
    color: #000;  
  } 
} 

@media (prefers-color-scheme: dark) { 
  .article {  
    background:#000;  
    color: #fff;  
  } 
} 

@media (prefers-color-scheme: no-preference) { 
  .article {  
    background:#fff; 
    color: #000;  
  } 
}
  • no-preference 表示系统未得知用户在这方面的选项,在布尔值上下文中,其执行结果为 false
  • light 表示用户已告知系统他们选择使用浅色主题的界面
  • dark 表示用户已告知系统他们选择使用暗色主题的界面

2.2 通过 js 监听

上述方法仅能在网页加载时获取一次主题,若用户切换主题时,页面是无法实时更换主题的。 但是上述媒体查询结果(MediaQueryLis)对象支持 addListener 方法监听主题变化。 通过监听就可以解决主题切换实时更新的额问题了。

const themeMedia = window.matchMedia("(prefers-color-scheme: light)");
themeMedia.addListener(e => {
	if (e.matches) {
	} else {
		console.log('dark')
	}
});

3.主题设置储存

当用户设定了主题之后,需要将选择主题信息进行保存,如果你有账户系统就可以将用户配置存储到用户数据表中。如果你的网站可以匿名访问,可以选择将主题样式存储到 localStorage 中:

const toggleButton = document.getElementById('toggle-theme');
const box = document.querySelector('.box');

toggleButton.addEventListener('click', () => {
    box.classList.toggle('dark');

    // 将用户选择保存到 localStorage
    const isDarkMode = box.classList.contains('dark');
    localStorage.setItem('darkMode', isDarkMode);
});

// 页面加载时检查并应用用户上次选择
if (localStorage.getItem('darkMode') === 'true') {
    box.classList.add('dark');
}

一般情况下,用户不主动清除浏览器缓存,则 localStorage 会一直生效。你也可以用 js 进行清除:

// 清除某个特定的键
localStorage.removeItem('darkMode');

// 清除所有的 localStorage 数据
localStorage.clear();

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

Next Post

续期你的Github学生包

周三 10 月 9 , 2024
两年前我写了一篇 Github 学生包的 […]