Element Plus 组件库相关技术揭秘:10. CSS 系统颜色和暗黑模式的关系及意义

本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究

前言

我们通过前面的文章可以知道在支持 CSS 变量的现代浏览器中,可以在运行时进行实时动态更新主题。而在 Element Plus 中已经使用 CSS 变量来重构了几乎所有组件的样式系统,也就是使用 SCSS 的函数自动生成需要用到的 CSS 变量。这意味着你可以动态地改变组件内的个别变量,以便更好地自定义组件样式,而不需要修改 SCSS 文件重新编译一次。

通过 CSS 变量,Element Plus 默认提供了“白天模式”和“夜间模式” (又或着叫:暗黑模式) 两种皮肤。“暗黑模式” 这个概念起初来源于 macOS 系统,该系统的 mojave 版本为用户提供两个主题皮肤,即浅色和深色的主题。自从有了这个概念之后,很多网站和系统都会为用户提供相应的两套样式,便于用户根据自己的习惯或爱好进行切换。Element Plus 也支持了这种模式。

CSS 系统颜色

我们想要理解什么是暗黑模式,以及怎么设置暗黑模式,我们先要了解CSS 系统颜色,因为CSS 系统颜色会根据系统的模式进行不同的渲染,当系统是黑暗模式的时候,会进行黑暗模式的渲染,其实就是颜色会根据系统模式的不同而发生变化,比如白的变成黑,黑的变成白。

我们假设有以下一段 HTML 代码。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS 系统颜色</title>
</head>
<body>
    <div>稀土掘金</div>
    <p>一个帮助开发者成长的社区</p>
    <h2>掘金签约作者:Cobyte</h2>
    <button>关注我</button>
    <input type="checkbox" name="is-support-checkbox" checked="checked">
    <input type="radio" name="is-support-radio" checked="checked">
    <input type="radio" name="is-support-radio">
</body>
</html>
复制代码

页面渲染结果如下:

02.png

我们可以看到我们并没有给上述的任何标签设置 CSS 样式,但浏览器仍然渲染出了默认的样式,这里我们关心的是它们的默认颜色,比如字体颜色,button 标签的边框颜色、背景颜色,复选框、单选框的选中颜色。当我们没有给它们设置颜色的时候,这些标签会使用CSS 系统颜色,那么这些系统颜色是什么呢?那么可以从官方文档中找到:CSS System Colors

03.png

有一些的 HTML 标签可以直接在浏览器的开发者工具中查看到使用了哪些系统颜色,比如 button 标签。

04.png

扫描二维码关注公众号,回复: 14545127 查看本文章

有一些在浏览器开发者工具中是看不到的,我们就需要从官方文档中进行查找了。从官方的文档中我们可以知道普通的标签的字体颜色默认是:WindowText,背景颜色是:Window。也就是默认的时候会给上述的 div、p、h2 标签设置以下样式:

div,p,h2 {
    color: WindowText; background-color: Window
}
复制代码

这些系统颜色也可以在不同的标签中互相使用,比如我们把 button 标签中使用到的系统颜色应用到 div、p、h2 中。

div,p,h2 {
    color: buttontext; background-color: buttonface
}
复制代码

页面渲染结果:

05.png

我们发现 div、p、h2 的背景颜色也变成了 button 标签一样的了,而字体颜色则不变,说明它们是一样的颜色。

通过官网文档我们还可以知道 checkbox 和 radio 标签的选中时的分别是 HighlightHighlightText,意思是选中的项目的颜色和选中项目的文本颜色。我们接着把 div、p、h2 标签的文本颜色设置:HighlightText,背景颜色设置为:Highlight

div,p,h2 {
    color: HighlightText; background-color: Highlight;
}
复制代码

页面渲染结果如下:

06.png

我们可以看到 div、p、h2 标签的文本颜色和背景颜色分别为 checkbox 和 radio 标签的选中时的文本颜色和选中的颜色。

那么我们对 CSS 系统颜色有一定了解之后,我们就可以对暗黑模式进行详细理解了。

CSS color-scheme 属性

Element Plus 默认提供了“白天模式”和“夜间模式” (又或着叫:暗黑模式) 两种主题,是通过color-scheme 实现的,所以我们有必要对 color-scheme 进行深入的了解。

01.gif

Element Plus 默认提供了“白天模式”和“夜间模式” 可以在官网文档上进行体验。

color-scheme 使用这个属性可以轻松的更改浏览器的默认配色方案,color-scheme 属性只有 4个,分别如下:

color-scheme: normal;
color-scheme: light;
color-scheme: dark;
color-scheme: light dark;
复制代码

根据 MDN 官方文档的介绍这个 4 个属性分别代表的意思是:

  1. normal 表示元素未指定任何配色方案,因此应使用浏览器的默认配色方案呈现。
  2. light 表示可以使用操作系统亮色配色方案渲染元素。
  3. dark 表示可以使用操作系统深色配色方案渲染元素。
  4. light dark 表示可选的配色方案,由系统来决定。

浅色模式和深色模式

那么上述的这些属性到底具体表示的是什么意思呢?我们需要从实践中进行进一步的理解。我们在前言中说到现在很多系统都提供了“浅色模式”和“深色模式” ,其中手机系统不管是 IOS 还是安卓目前也都提供了这两种模式。

08.png

macOS系统中的“浅色模式”和“深色模式”设置。

14.png

手机端访问本地电脑服务器

由于我们需要在手机端进行预览验证,所以我们需要通过 Live Server 启动通过 HTTP 方式访问页面。接着我们需要在命令终端通过 ipconfig 命令查看我们本地IP 的地址。

09.png

这样我们就可以通过局域网的本地的 IP 地址在手机上也可以访问我们电脑上的服务器了,前提是我们的手机也和电脑同处一个局域网内,比如手机通过 WIFI 链接网络。

我们通过 Live Server 启动的页面 URL 地址为:http://127.0.0.1:5500/index.html,现在我们知道了局域网的IP 地址后,我们可以把 URL 地址改为:http://192.168.31.101:5500/index.html,这样当手机端和本地电脑同在一个局域网的话,手机端就可以通过 http://192.168.31.101:5500/index.html 地址访问本地电脑上的服务器了。

现在在根元素上添加 color-scheme 属性,并设置为 normal,也就是使用系统的默认配色方案。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS color-scheme 和暗黑模式</title>
    <style>
        :root{
            color-scheme: normal;
        }
    </style>
</head>
<body>
    <div>稀土掘金</div>
    <p>一个帮助开发者成长的社区</p>
    <h2>掘金签约作者:Cobyte</h2>
    <button>关注我</button>
    <input type="checkbox" name="is-support" checked="checked">
    <input type="radio" name="is-support" checked="checked">
    <input type="radio" name="is-support">
</body>
</html>
复制代码

PC端页面渲染结果如下:

02.png

手机端页面渲染结果如下:

11.png

上述渲染结果是使用操作系统浅色模式时的渲染结果。当我们使用操作系统深色模式时的渲染结果则如下:

12.png

这个时候我们看到原来白色的背景变成黑色了,黑色的字体也变成白色的字体了。这个时候我们就可以理解 color-scheme 属性为 normal 时的含义了,就是根据操作系统设置的配色方案进行渲染页面。为什么可以做到这样呢?就是我们上面提到的 CSS 系统颜色起到的作用。因为CSS 系统颜色会根据系统的模式进行不同的渲染,当系统是黑暗模式的时候,会进行黑暗模式的渲染

chrome 浏览器设置暗黑模式

上述验证方案是在手机系统上进行验证的,那么又怎么在 PC 端进行验证呢?因为 win 系统是没有暗黑模式的,所以需要在浏览器上进行设置。

打开浏览器,在地址栏中输入黑色模式指令:chrome://flags/#enable-force-dark

10.png

然后就可以找到 Force Dark Mode for Web Contents 选项,接着把 Default 改成 Enabled ,再点击 Relaunch 重启浏览器就设置成功了。

我们可以看到当把 color-scheme 属性为 normal 时是需要用户对操作系统的配色进行设置的,这样显得比较麻烦,特别是 win 系统的 PC 端的设置更为繁琐。所以我们可以通过 color-scheme 属性设置指定的配色渲染方案。

如何设置浅色模式

我们接着把 color-scheme 设置为:light,浏览器则会以浅色模式进行渲染。

:root{
    color-scheme: light;
}
复制代码

渲染结果:

02.png

我们可以看到使用操作系统亮色配色方案渲染元素时,是和没有设置 color-scheme: light 时是一样的,也就说明操作系统默认的配色方案就是 light(亮色或者叫白天模式又或者叫浅色模式)。

如何设置暗黑模式

我们接着把 color-scheme 设置为:dark,浏览器则会以暗黑模式进行渲染。

:root{
	color-scheme: dark;
}
复制代码

页面的渲染结果如下:

07.png

这个时候我们看到渲染结果和操作系统设置暗黑模式时的渲染结果是一样的,而且只需要设置一行代码:color-scheme: dark ,就可以实现一样的效果了,这是浏览器按照暗黑模式进行渲染的结果。

小结:CSS 系统颜色和暗黑模式

至此我们就可以把 CSS 系统颜色和暗黑模式之间的关系搞清楚了。CSS 系统颜色会根据系统的模式进行不同的渲染,当系统是黑暗模式的时候,会进行黑暗模式的渲染,当系统是浅色模式时,则会进行亮色模式的渲染,就是默认模式的渲染。本质就是颜色发生变化,比如白的变成黑,黑的变成白。

根据系统的配色设置来渲染页面,太过繁琐,所以可以直接通过 color-scheme 设置指定要渲染的模式,color-scheme 设置为 light 时则进行浅色模式的渲染,color-scheme 设置为 dark 时则进行暗黑模式的渲染。

值得注意的是,暗黑模式只对系统颜色起作用,但系统颜色比较有限,所以难以满足我们设计需求。我们在平时的开发中会根据UI设计师给的颜色进行设置我们的 HTML 标签颜色,而这些自定义设置的颜色是不会受暗黑模式影响的,所以我们在设计亮色模式和暗黑模式的主题色,还是根据我们传统的设置来实现,但可以在我们设置的常规暗黑模式下添加 color-scheme: dark 作为兜底方案,可以很好的适配浏览器原生样式。

通过 CSS 变量实现一键换肤

Element Plus 默认提供了“白天模式”和“夜间模式” (又或着叫:暗黑模式) 两种皮肤,那么它 是怎么实现的呢?

传统模式 事先写好“白天模式”和“夜间模式”的样式。

html.light{
    color: #000;
    background-color: #fff; 
}
html.dark{
    color: #fff;
    background-color: #000;
}
复制代码

再通过 JavaScript 切换 class。

<h2>掘金签约作者:Cobyte</h2>
<button id="skin-btn">一键换肤</button>
<script>
    const skinBtn = document.getElementById('skin-btn')
    const html = document.documentElement;
    skinBtn.onclick = () => {
        if(html.className !== 'dark') {
            html.setAttribute('class', 'dark');
        } else {
            html.setAttribute('class', 'light');
        }
    }
</script>
复制代码

实现效果如下:

skins-change.gif

这种模式存在诸多问题,比如需要写不同的样式代码,会导致代码量增大,维护麻烦,拓展性等。 我们在前言中说到了,B 端的所谓主题切换,更多的是颜色、字体大小的更改。在 CSS 变量诞生以后我们可以通过 CSS 变量来进行换肤,这样我们不同的主题色,我们只需要更改相关颜色变量即可。

我们只需要把上面的 CSS 样式部分代码进行以下改造即可。

body {
    color: var(--text-color);
    background-color: var(--bg-color);
}

html.light{
    --text-color: #000;
    --bg-color: #fff; 
}
html.dark{
    --text-color: #fff;
    --bg-color: #000;
}
复制代码

实现效果如下:

css-var-change-skin.gif

我们可以看到右侧样式部分的动态渲染结果,所谓换肤,只是改变 CSS 变量的值而已,这样就可以大大提高我们的换肤功能的灵活性。同时为了更好地呈现我们的暗黑模式,我们可以分别给我们的亮色模式和暗黑模式分别设置 color-scheme 属性,以浏览器的原生模式作为兜底。比如我们上面的 button 标签的样式,暗黑模式的时候我们是没有进行特别的设置的,在自定义的暗黑模式下就显得比较不柔和。

以浏览器的原生模式作为兜底

所以我们进行以下设置。

html.light{
    color-scheme: light;
    --text-color: #000;
    --bg-color: #fff; 
}
html.dark{
    color-scheme: dark;
    --text-color: #fff;
    --bg-color: #000;
}
复制代码

暗黑模式的渲染结果:

13.png

可以看到当我们在暗盒模式添加了 color-scheme: dark 之后,button 按钮在暗黑模式下的渲染效果就柔和很多了。通过上文我们可以知道其中的原理,当我们没有给相关标签定义相关颜色的时候,它们会使用默认的CSS 系统颜色CSS 系统颜色会根据系统模式的不同,进行不同颜色的渲染。这就是使用浏览器的原生模式作为兜底的原因了。这也是本文重点要说明的 CSS 系统颜色和暗黑模式的关系及意义

总结

我们通过文本知道了什么是CSS 系统颜色,什么是暗黑模式,以及怎么设置暗黑模式

CSS 系统颜色会根据系统的模式进行不同的渲染,当系统是黑暗模式的时候,会进行黑暗模式的渲染,当系统是浅色模式时,则会进行亮色模式的渲染,就是默认模式的渲染。本质就是颜色发生变化,比如白的变成黑,黑的变成白。

根据系统的配色设置来渲染页面,太过繁琐,所以可以直接通过 color-scheme 设置指定要渲染的模式,color-scheme 设置为 light 时则进行浅色模式的渲染,color-scheme 设置为 dark 时则进行暗黑模式的渲染。

值得注意的是,暗黑模式只对系统颜色起作用,但系统颜色比较有限,所以难以满足我们设计需求。我们在平时的开发中会根据UI设计师给的颜色进行设置我们的 HTML 标签颜色,而这些自定义设置的颜色是不会受暗黑模式影响的,所以我们在设计亮色模式和暗黑模式的主题色,还是根据我们传统的设置来实现,但可以在我们设置的常规暗黑模式下添加 color-scheme: dark 作为兜底方案,可以很好的适配浏览器原生样式

我们这里讨论的主题更换都是 B 端的范畴,因为 C 端的主题变化范围相对 B 端更大,B 端的所谓主题切换,更多的是颜色、字体大小的更改,也就是皮肤的更改,所以也叫:一键换肤。C 端则可能页面布局结构都不一样,对于此类主题的更换使用到的技术范畴是完全不一样的,目前更多通过低代码平台实现托拉拽进行更换不同的页面布局,同时更换颜色、字体大小。

我们将在下一篇文章中继续学习研究 Element Plus 中的 SCSS 样式架构。

欢迎关注本专栏,了解更多 Element Plus 相关知识。

本专栏文章:

1. Vue3 组件库的设计和实现原理

2. 组件库工程化实战之 Monorepo 架构搭建

3. ESLint 核心原理剖析

4. ESLint 技术原理与实战及代码规范自动化详解

5. 从终端命令解析器说起谈谈 npm 包管理工具的运行原理

6. CSS 架构模式之 BEM 在组件库中的实践

7. 组件实现的基本流程及 Icon 组件的实现

8. 为什么组件库或插件需要定义 peerDependencies

9. Button 组件的实现及 Vue3 相关知识的应用与解析

10. CSS 系统颜色和暗黑模式的关系及意义

猜你喜欢

转载自juejin.im/post/7186683381470462007