Skip to content
字数
571 字
阅读时间
3 分钟

暗色模式-实现支持跟随系统自动变化与手动设置的明暗模式切换

明暗跟随系统的实现方式

跟随系统的明暗模式可以通过媒体查询 prefers-color-scheme: {dark|light} 去实现,例如下面这样:

less
@media (prefers-color-scheme: dark) {
  color: #FFFFFF;
  background-color: #171717;
}

实现支持手动修改

但是如果我们要同时支持用户在页面上手动修改,则需要通过 JavaScript 去控制,使用 matchMedia 函数可以在 JS 脚本中进行媒体查询来获取当前的 prefers-color-schem状态,并根据条件修改 body 的 class 加上 .theme-dark 类。具体代码实现如下:

util/darkMode.ts

typescript
// util/darkMode.ts
type ColorMode = 'auto' | 'light' | 'dark'

const classDarkName = 'theme-dark'
const cookieName = 'color-mode'
const body = document.getElementsByTagName('body')[0] as HTMLBodyElement

/** 检查夜间模式是否需要生效 */
export function checkDarkMode() {
  const mode = window.localStorage && window.localStorage.getItem(cookieName)
  // 自动模式
  if (!mode || mode === 'auto') {
    if (typeof matchMedia === 'function' && matchMedia('(prefers-color-scheme: dark)').matches)
      body.classList.add(classDarkName)
    else
      body.classList.remove(classDarkName)
  }
  // 手动模式
  else {
    if (mode === 'dark')
      body.classList.add(classDarkName)
    else
      body.classList.remove(classDarkName)
  }
}

/** 切换明暗主题 */
export function setColorMode(mode: ColorMode) {
  window.localStorage && window.localStorage.setItem(cookieName, mode)
  checkDarkMode()
}

然后在界面加载完成后注册 prefers-color-scheme 的事件监听器,如果是 Vue 的话,将如下代码写入 mounted 函数中。

App.vue

typescript
// App.vue > mounted
import { checkDarkMode } from './util/darkMode'
// 初始化状态
checkDarkMode()

// 将 checkDarkMode 添加为媒体查询"prefers-color-scheme: dark" 的事件监听器
const darkMedia = typeof matchMedia === 'function' && matchMedia('(prefers-color-scheme: dark)')
if (darkMedia && typeof darkMedia.addEventListener === 'function') {
  darkMedia.addEventListener('change', checkDarkMode)
}

然后在你喜欢的地方添加一个 明暗模式选择按钮,并吧 setColorMode 绑定上 Click

添加具体的黑暗模式样式

完成如上步骤之后,明暗切换就可以正常工作啦,接下来我们要给每个页面添加暗色模式下的 class 样式

这一步如果使用的是调色板设计的话,会不太一样,这边展示的是单独修改页面样式的情况

less
// pages/xxx.vue > style
// <style lang="less" scoped>
.bg {
  background-color: #f9f9f9;
  .card {
    color: black;
    background-color: white;
  }
}

// 将 class 定义为 .theme-dark 的子类,实现只在暗色模式下启用的效果。
// 这里可以开启 scoped,不会有影响
.theme-dark .bg {
  background-color: #171717;
  .card {
    background-color: #1d1d1d;
    color: #f1f2f5;
  }
}

贡献者

页面历史

撰写