主题切换解决方案

现在我们经常可以看到一些网站会有类似暗黑模式/白天模式的主题切换功能,效果也是十分炫酷,在平时的开发场景中也有越来越多这样的需求,尤其是后台管理系统、企业官网、文章、试题项目中更加普遍,下面简单罗列几种解决方案:

1.通过修改link标签来切换样式

其做法就是提前准备好几套CSS主题样式文件,在需要的时候,创建link标签动态加载到head标签中,或者是动态改变link标签的href属性。

    <link rel="stylesheet " href="./dark.css" ty="darkTheme" >
    <link rel="stylesheet" href="./light.css" ty="lightTheme">

效果如下:
m0wcdk0y.png
m0wcehij.png

优点:实现了按需加载,提高了首屏加载时的性能

缺点:动态加载样式文件,如果文件过大网络情况不佳的情况下可能会有加载延迟,导致样式切换不流畅,如果主题样式表内定义不当,会有优先级问题,各个主题样式是写死的,后续针对某一主题样式表修改或者新增主题也很麻烦

2.提前引入所有主题样式,做类名切换

在需要切换主题的时候将指定的根元素类名更换,相当于直接做了样式覆盖,在该类名下的各个样式就统一地更换了。其基本方法如下:

  /* light亮色主题 */
  body.light .box {
    color: #f90;
    background: #fff;
  }
  /* dark暗色主题 */
  body.dark .box {
    color: #eee;
    background: #333;
  }

跟第一种相比:不用重新加载样式文件,在样式切换时不会有卡顿。但是首屏加载时会牺牲一些时间加载样式资源,各个主题样式是写死的,后续针对某一主题样式表修改或者新增主题也很麻烦

3.CSS变量+类名切换

灵感参考: Vue3.0官网
m0wclr6t.png
m0wcm3v0.png
Vue的官网在切换主题时就非常的丝滑,同时还使用了 color-scheme: dark; 将系统的滚动条设置为了黑色模式,使样式更加统一。

思路方案和第2种差不多,依然是提前将样式文件载入,切换时将指定的根元素类名更换。不过这里相对灵活的是,默认在根作用域下定义好CSS变量,只需要在不同的主题下更改CSS变量对应的取值即可。

  :root {
    --BG: #14191C;
    --TextColor: #FFFFFF;
    --TextColorLight: #0095B7;
    --eduColor: #0095B7;
    --expColor: #FF7F00;
  }
  /* 更改dark类名下变量的取值 */
  .dark{
    --theme-color: #eee;
    --theme-background: #333;
  }
  /* 更改pink类名下变量的取值 */
  .light{
  --theme-color: #000000;
  --theme-background: #ffffff;
  }

  .box {
    transition: all .2s;
    width: 100px;
    height: 100px;
    border: 1px solid #000;
    /* 使用变量 */
    color: var(--theme-color);
    background: var(--theme-background);
  }

优点:

  • 不用重新加载样式文件,在样式切换时不会有卡顿
  • 在需要切换主题的地方利用var()绑定变量即可,不存在优先级问题
  • 新增或修改主题方便灵活,仅需新增或修改CSS变量即可,在var()绑定样式变量的地方就会自动更换

缺点:其实也没啥缺点,硬要说就是适配IE浏览器或者是首屏加载速度的问题

一般在工作中我都使用第三种,这些都是自己定义的,如果要用户端自己根据拾色板来确定要是的话,可以使用如下方案:

CSS变量+动态setProperty

这种方案主要用于是主题颜色不确定的情况

参考项目: ElementAdmin

m0wd9v0e.png

主要实现思路如下:
只需在全局中设置好预设的全局CSS变量样式,无需单独为每一个主题类名下重新设定CSS变量值,因为主题是由用户动态决定。

  :root {
    --theme-color: #333;
    --theme-background: #eee;
  }

定义一个工具类方法,用于修改指定的CSS变量值,调用的是 CSSStyleDeclaration.setProperty

  export const setCssVar = (prop: string, val: any, dom = document.documentElement) => {
    dom.style.setProperty(prop, val)
  }

在样式发生改变时调用此方法即可

  setCssVar('--theme-color', color)

刷掘金看到了评论用滤镜反色效果的 filter:invert(1);

m0wdql6o.png

用在掘金上乍一看还凑合,但是自己的项目就不太行了,这个只能当个玩笑,不建议使用!

m0wdoqwi.png

打赏
评论区
头像