DEMO
定义色板
:root {
  --blue: royalblue;
  --red: tomato;
  --black-100: rgba(0,0,0,1);
  --black-80: rgba(0,0,0,.8);
  --black-60: rgba(0,0,0,.6);
  --black-40: rgba(0,0,0,.4);
  --black-20: rgba(0,0,0,.2);
  --white-100: rgba(255,255,255,1);
  --white-80: rgba(255,255,255,.8);
  --white-60: rgba(255,255,255,.6);
  --white-40: rgba(255,255,255,.4);
  --white-20: rgba(255,255,255,.2);
}
预先定义好所有要用到的颜色,色板的颜色与主题无关,供主题取色
定义主题
.dark {
  color-scheme: dark;
  --bg: var(--black-100);
  --text: var(--white-100);
}
.light {
  color-scheme: light;
  --bg: var(--white-100);
  --text: var(--black-100);
}
定义了dark和light两套主题,主题内的变量是有UI语义的,变量名代表了具体UI 值是从色板取的具体颜色
主题模式实现
Theme代表了具体的主题定义,而Theme Mode是UI的主题模式 是供用户手动选择的(默认System),我们要根据UI的模式来动态切换主题定义,通常有3种模式 system light dark
System 跟随系统模式
@media(prefers-color-scheme: dark) {
  :root:not(.light):not(.dark) {
    --bg: var(--black-100);
    --text: var(--white-100);
  }
}
@media(prefers-color-scheme: light) {
  :root:not(.light):not(.dark) {
    --bg: var(--white-100);
    --text: var(--black-100);
  }
}
媒体查询自动响应系统主题来修改主题变量,代码完全是和.dark .light重复的,因为我是用纯css举例,实际开发中用scss less等工具能用@mixin复用代码
Dark、Light 亮色暗色模式
这一步就要用🤏🏻js代码来实现,只需要切换html的class name就行,亮色.light 暗色.dark
const system = document.getElementById('system')
const light = document.getElementById('light')
const dark = document.getElementById('dark')
const root = document.documentElement
system.onclick = ()=>{
  root.classList.remove('light', 'dark')
}
light.onclick = ()=>{
  root.classList.remove('dark')
  root.classList.add('light')
}
dark.onclick = ()=>{
  root.classList.remove('light')
  root.classList.add('dark')
}
持久化
用户选择模式后 下次今天要记忆上次的模式,这就需要持久化,很简单 只需要把theme mode保存到localstrage里,然后每次打开页面读取一下 然后设置模式 就可以了,具体代码不演示了。