Skip to content
文章目录

深色模式与多主题

css 变量

本文章多使用 css 变量方式实现多主题和深色模式,因此请先了解 css 变量,如果对 css 变量不了解,请先阅读这篇文章《css 变量》

跟随系统设置

使用 CSS 媒体查询匹配系统设置。prefers-color-scheme 用于检测用户是否有将系统的主题色设置为亮色或者暗色。

css
// 用户选择选择使用浅色主题的系统界面
@media (prefers-color-scheme: light) {
}

// 用户选择选择使用深色主题的系统界面
@media (prefers-color-scheme: dark) {
}

// 表示系统未得知用户在这方面的选项
@media (prefers-color-scheme: no-preference) {
}

使 JavaScript matchedMedia API 匹配操作系统主题。如果对 window.matchMedia 不了解,请先看这篇文章《window.matchMedia 响应分辨率和操作系统主题模式变化》

js
function onOperateSystemChange(prefersDarkScheme) {
  if (prefersDarkScheme.matches) {
    // 用户操作系统主题设置为 dark
  } else {
    // 用户操作系统主题设置为 非dark
  }
}

const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)')
// 添加监听
prefersDarkScheme.addEventListener(onOperateSystemChange)
// 删除监听
prefersDarkScheme.removeListener(onOperateSystemChange)

深色、浅色模式, 多主题的实现

关于如何根据一个主题色使用 JS 生成一系列的次级衍生色,请见这篇文章:《chroma-js 进行颜色操作》

css
:root {
  --color: #555;
}
:root[theme='dark'] {
  --color: #fff;
}
body {
  color: var(--color);
}
@media (prefers-color-scheme: dark) {
  :root {
    --color: #fff;
  }
}

<html> 的属性 theme 的值不为 "dark" 时,var() 函数读取的是 :root{} 内的自定义属性(浅色模式匹配的的自定义属性),反之,则读取的是 :root[theme="dark"] 中的自定义属性。同样也可以结合媒体查询,实现跟随系统的效果

好处是扩展性更强,代码量较少,代码维护方便。不仅可以切换到深色模式,还可以切换到其他主题。 例如给 html 的 theme 属性设置其他值 <html theme="pink"> ,只需要添加下面这段 css:

css
:root[theme='pink'] {
  --color: pink;
}

通过 JavaScript 给 <html> 的 theme 属性赋值为 "pink" ,就能切换到该主题。

js
const button = document.querySelector('.toggle')
button.addEventListener('click', function () {
  document.documentElement.setAttribute('theme', 'pink')
})

css 变量命名

--[attribute]-[element]-[elementAttribute]-[x]: [value]

粗粒度命名

css
:root {
  --primary: #0097ff;
  --secondary: #6c757d;
  --success: #28a745;
  --info: #17a2b8;
  --warning: #ffc107;
  --danger: #dc3545;
  --color-basic-50: #ffffff;
  --color-basic-75: #fafafa;
  --color-basic-100: #f5f5f5;
  --color-basic-200: #eaeaea;
  --color-basic-300: #e1e1e1;
  --color-basic-400: #cacaca;
  --color-basic-500: #b3b3b3;
  --color-basic-600: #8e8e8e;
  --color-basic-700: #6e6e6e;
  --color-basic-800: #4b4b4b;
  --color-basic-900: #2c2c2c;
}

细粒度命名

css
:root {
  --color-text-primary: #555;
  // ...
}
:root {
  --color-notifications-button-hover-text: var(--color-text-primary);
  // ...
}

图片处理

css
img.dark {
  filter: brightness(0.8) contrast(1.2);
}
  • brightness 使图像看起来更亮或更暗
  • contrast 调整图像的对比度

图片对比

阴影处理

让设计师给出不同主题的 shadow

主题切换过渡动画

使用 CSS 伪元素创建一个带有过渡效果的蒙层,在切换时给文档的根元素添加一个 class,通过给此 class 添加伪元素以创建带有过渡动画的蒙层。例如,在浅色切换到深色时 class 为 light-to-dark,反之,为 dark-to-light。

scss
$mode: () !default;
$mode: map-merge(
  (
    bg-light: #fff,
    bg-dark: #252528,
  ),
  $mode
);

$bg-light: map-get($mode, bg-light);
$bg-dark: map-get($mode, bg-dark);

.dark-to-light:after {
  content: '';
  width: 100vw;
  height: 100vh;
  position: fixed;
  z-index: 99999;
  left: 0;
  top: 0;
  margin-left: 0;
  background-color: $bg-dark;
  opacity: 0.7;
  animation: toLight 1s linear 0s forwards;
  // pointer-events: none;
}

.light-to-dark:after {
  content: '';
  width: 100vw;
  height: 100vh;
  position: fixed;
  z-index: 99999;
  left: 0;
  top: 0;
  margin-left: 0;
  background-color: $bg-light;
  opacity: 0.7;
  animation: toDark 1s linear 0s forwards;
  // pointer-events: none;
}

@keyframes toLight {
  0% {
    background-color: $bg-dark;
    opacity: 0.7;
  }
  100% {
    background-color: $bg-light;
    opacity: 0;
  }
}
@keyframes toDark {
  0% {
    background-color: $bg-light;
    opacity: 0.7;
  }
  100% {
    background-color: $bg-dark;
    opacity: 0;
  }
}

在切换模式时,将会在页面顶层展示带有对应过渡效果的蒙层。在过渡效果显示时,用户的鼠标无法点击页面的元素,这样做同时实现了类似防抖的效果。如果想移除这个效果,只需给蒙层加上 pointer-events: none;

储存状态

仅仅通过点击按钮切换主题还不够,应该将主题保存起来。否则,用户刷新页面或者再此进入页面将回到初始主题。在切换主题或者初始化时都应该使用状态储存。

js
localStorage.setItem("theme", <"dark" | "light">); // 存储
localStorage.getItem("theme"); // 读取

灰度模式

使用 css filter, 给网站根元素设置filter: grayscale(100%);,整个网站就变为灰颜色了

如果需要兼容 IE

css
html {
  -webkit-filter: grayscale(100%);
  filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
}
灰度效果

参考资料

深色模式适配和主题切换