Skip to content

原生css变量

自动随系统切换深色模式

利用prefers-color-scheme 媒体查询检测网页是深色模式还是日间模式 媒体查询优先级 浏览器的外观模式 > 系统的外观模式

css
@media (prefers-color-scheme: light | dark) {
  :root{}
  body{}
}

适用于自动随系统切换2种主题色的场景,多主题色时不适用 需要留意兼容性can i use

create-vue脚手架初始化出来的项目:

css
/* 颜色变量 from <https://github.com/vuejs/theme> */
:root {
  --vt-c-white: #ffffff;
  --vt-c-white-soft: #f8f8f8;
  --vt-c-white-mute: #f2f2f2;

  --vt-c-black: #181818;
  --vt-c-black-soft: #222222;
  --vt-c-black-mute: #282828;

  --vt-c-indigo: #2c3e50;

  --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
  --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
  --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
  --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);

  --vt-c-text-light-1: var(--vt-c-indigo);
  --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
  --vt-c-text-dark-1: var(--vt-c-white);
  --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}

/* 默认主题色变量 白色 */
:root {
  --color-background: var(--vt-c-white);
  --color-background-soft: var(--vt-c-white-soft);
  --color-background-mute: var(--vt-c-white-mute);

  --color-border: var(--vt-c-divider-light-2);
  --color-border-hover: var(--vt-c-divider-light-1);

  --color-heading: var(--vt-c-text-light-1);
  --color-text: var(--vt-c-text-light-1);

  --section-gap: 160px;
}
/* 深色模式变量 */
@media (prefers-color-scheme: dark) {
  :root {
    --color-background: var(--vt-c-black);
    --color-background-soft: var(--vt-c-black-soft);
    --color-background-mute: var(--vt-c-black-mute);

    --color-border: var(--vt-c-divider-dark-2);
    --color-border-hover: var(--vt-c-divider-dark-1);

    --color-heading: var(--vt-c-text-dark-1);
    --color-text: var(--vt-c-text-dark-2);
  }
}

编写业务代码的时候使用变量(得益于原生css变量定义在:root上,业务代码不需要手动引入css资源)

css
.content {
  background: var(--color-background);
}

小结:

  • 业务代码需要用css变量编写颜色,如果是现有项目做支持需要考虑全量修改代码的影响
  • 1个颜色变量对应2种值,如上写法,颜色值虽好维护,颜色变量2种值的映射则需要手动重复在媒体查询内编写
  • 深色模式时,会闪一次白色(可以加一点动画实现渐变到黑色的效果,但是闪白色还是避免不了)
  • TODO: 第三方组件库如何支持覆写样式使用颜色变量
  • TODO: 自动决定主题色,扩展开关切换,优先级:手动(存sessionStore即可)>浏览器>系统

js手动控制主题色

预先定义好不同主题原生CSS变量,通过js动态切换公共类名来达到换肤效果

.root 表示 <html> 元素,除了优先级更高之外,与 html 选择器相同。 除了css选择器有样式优先级,样式引入方式也有优先级,综合引入方式和选择器的优先级是什么

直接写属性选择器是什么操作,[data-theme:"dark"] {} 为什么html选择器也是只能写在root上面

为什么分开属性选择的样式文件和:root的样式并让属性选择器顺序在下面引入,就可以做到优先级更高 (普通选择器不会因为分离文件就样式优先级更高)

在乎顺序,在同一文件里属性选择器在:root上才能生效,并且优先级比root低(优先级低会因为顺序?)

根标签或html影响的可不止是body,还有head呢 通配符*那就完全不一样了,是选中所有元素 有些属性的设置是不继承的,所以区分这些是非常有意义的

:root或html里面会写一些css变量 *在去除默认样式的时候非常常用 body那就不用我说了吧,能实际看到的,你想他长啥样就设置他就对了

直接写属性选择器,表示所有有该属性的元素都选中,常用写法会局限具体的选择器加上属性,不代表不能直接用属性选择器

在这个示例代码里,属性选择器的结果就是html标签,全等 也就是html选择器也不能写在:root下面 通过另外写文件并置于下面,可以让html选择器的优先级高于:root 这样感觉:root和html选择器完全就是同一个选择器了因为优先级跟顺序有关 :root存在的意义又是什么 那为什么定义css变量要定义在:root而不是html呢(优先级高?写起来更好看?)

多套主题样式文件

方案一: 预先定义好不同主题原生CSS变量,通过js动态切换公共类名来达到换肤效果

方案二: 预先打包出不同主题样式css,js动态加载不同的样式表,如下: * theme-green.css * theme-red.css * theme-black.css

方案三: localStorage存储主题,js动态获取本地存储换肤

方案四: element和antd的动态换肤,需要实时编译style样式表

类似element-ui做的换肤,把颜色的样式都写在head头部的style标签里面,当换颜色的时候,style标签id为docs-style和chalk-style里面的颜色就会被替换

oo

html
<style id="colorId">
  .bg{
    background: #00aaee;
  }
  .text{
    color: #00aaee;
  }
</style>
<li><button class="bg" onclick="changeColor('00aaee')">a皮肤</button></li>
<li><button class="bg" onclick="changeColor('00ee57')">b皮肤</button></li>
<li><button class="bg" onclick="changeColor('ee0043')">c皮肤</button></li>
js
let currentColor = '00aaee';
function changeColor(color) {
  let sty = document.getElementById('colorId');
  let str = sty.innerHTML;

  let reg = new RegExp(currentColor,'g');
  str = str.replace(reg, color);
  sty.innerHTML = str;
  currentColor = color;
}

真正要实现起来当然要复杂一些,颜色肯定不止一个,element是颜色对应一个关键字的数组,然后把style里面的颜色都先替换成关键字,然后再根据颜色生成对应的数组,接着把关键字替换回颜色,最后写入style标签。

另外一种antd利用 Less 的变量以及在浏览器编译没有去实验一下,本地连antd的官网都打不开。还有之前有提到过的css in js在这种换肤场景下好像也非常的合适。

图片的暗黑模式?

有css图片样式可以调整图片亮度,背景图待查 仅仅是调整图片亮度,该白还是白

tailwindcss的暗黑模式

webpack的postcss

假如给HMBA设计换肤功能

自己的组件库,可以修改代码支持颜色变量

难点是存量业务代码太多,手动修改全部业务代码样式不智能(组件先支持暗黑模式,业务页面不得不支持,或者精确控制业务功能不切换组件主题)

给管理系统设计换肤功能

要考虑第三方组件样式和业务样式 业务样式可以修改代码支持颜色变量,第三方组件不能直接修改代码来支持变量

参考资料