前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DarkMode(2):深色模式解决方案——css颜色变量实现Dark Mode

DarkMode(2):深色模式解决方案——css颜色变量实现Dark Mode

原创
作者头像
周陆军
发布2020-12-11 22:33:16
3K0
发布2020-12-11 22:33:16
举报
文章被收录于专栏:前端架构前端架构

暗黑模式实现,最初的设计,就是参考之前的主题模式。所谓多套主题/配色/皮肤,就是我们很常见的换肤功能。换肤简单的实现就是更换 css实现不同样式呈现不同肤色。

之前做不同颜色的皮肤,暗黑模式可以单做其中的一种黑色暗黑主题。

通用的方法,就是less、sass、post-css,把颜色抽离出变量。然后打包输出不同的样式,即:

CSS预处理直接生成多套主题样式

  • 利用Less,stylus 或 sass 的变量代替颜色值
  • 配置多个主题颜色配置
  • 利用grunt/gulp/webpack等工具输出多套主题样式
  • 页面加载后,根据用户需求加载不同的样式列表

推荐阅读《webpack 换肤功能多主题/配色样式打包解决方案》,配置文件:

https://github.com/hiyangguo/webpack-mutiple-theme-bundle-css-demo/blob/master/webpack.config.js

这里是以less 为例,sass 配置,稍微修改即可,这里就不做赘述了,google应该都可以搜索得到,推荐这篇也是顺手搜的

这种方式在bootstrap时代就流行开来,那时候还用过php编译less,以及java编译:java -jar js.jar less-rhino-1.4.0.js listing3.less > listing3.css

webpack loader?modifyVars 生成多套样式

webpack 本身并不具备打包 less 文件的功能,最终实现该部分功能的是 less-loader,该加载器把 less 转为 CSS,在 webpack 中每个文件或模块都是有效的 JS 模块,因此我们还需要 css-loader 将CSS样式文件转换为变成 JS 模块。

这时我们已经有了生成的 dist/style.js,在这个模块中只是将样式导出为字符串并存放于数组中,我们需要 style-loader 将该数组转换成 style 标签。

less-loader?可以帮忙我们实现主体定制,通过一下这两个配置,我们就可以把部分样式抽出变量,通过不同的变量组合成不同的主题:

  • globalVars:相当于给每个 less 文件顶部增加一行 @VariableName: xx;
  • modifyVars:相当于给每个 less 文件底部增加一行变量 @variable:xx;

比如ant-design定制主题,官方demo:https://ant.design/docs/react/customize-theme-cn

其实这个和第一种方法差不多,目前facebook youtube 等,都是采用css 变量来实现

媒体查询与css变量实现

现在可以利用

二者配合就可以实现页面主题跟随系统自动切换深浅模式 。

CSS 的媒体查询

prefers-color-scheme?是一种用于检测用户是否有将系统的主题色设置为亮色或者暗色的 CSS 媒体特性。 利用其设置不同主题模式下的 CSS 样式,浏览器会自动根据当前系统主题加载对应的 CSS 样式。light 适配浅色主题,dark 适配深色主题,no-preference 表示获取不到主题时的适配方案。

CSS

代码语言:javascript
复制
@media?(prefers-color-scheme:?light)?{
????.article?{
????????background:#fff;
????????color:?#000;
????}
}
@media?(prefers-color-scheme:?dark)?{
????.article?{
????????background:#000;
????????color:?white;
????????}
}
@media?(prefers-color-scheme:?no-preference)?{
????.article?{
????????background:#fff;
????????color:?#000;
????}
}

Link 标签

代码语言:javascript
复制
<link?href="./common.css"?rel="stylesheet"?type="text/css"?/>
<link?href="./light-mode-theme.css"?rel="stylesheet"?type="text/css"?/>
<link?href="./dark-mode-theme.css"?rel="stylesheet"?type="text/css"?media="(prefers-color-scheme:?dark)"?/>

一般推荐使用link标签解决

CSS 变量 + 媒体查询

window.matchMedia (https://developer.mozilla.org/zh-CN/docs/Web/API/Window/matchMedia) 方法可以用来查询 指定的媒体查询字符串解析后的结果。 结合 CSS 变量和 matchMedia 的查询结果,设置对应的 CSS 主题颜色。该方法更灵活,可以单独抽离主题色进行适配。

CSS 变量的作用域与 CSS 的"层叠"规则一致,优先级最高的声明生效。所以当 body 上存在 "dark" 类名时,:root .dark 会生效,否则 :root 生效。

代码语言:javascript
复制
.article?{?
??color:?var(--text-color,?#eee);?
??background:?var(--text-background,?#fff);?
}?
:root?{?
??--text-color:?#000;?
??--text-background:?#fff;?
}?
:root?.dark?{?
??--text-color:?#fff;?
??--text-background:?#000;?
}

使用 matchMedia 匹配主题媒体,深色模式匹配 (prefers-color-scheme: dark) ,浅色模式匹配 (prefers-color-scheme: light) 。

监听主题模式,深色模式时为 body 添加类名 dark,根据 CSS 变量的响应式布局特点,自动生效 dark 类名下的 CSS。

代码语言:javascript
复制
const?darkMode?=?window.matchMedia?&&?window.matchMedia('(prefers-color-scheme:?dark)');?
//?判断是否匹配深色模式?
if?(darkMode?&&?darkMode.matches)?{?
??document.body.classList.add('dark');?
}?
//?监听主题切换事件?
darkMode?&&?darkMode.addEventListener('change',?e?=>?{?
??if?(e.matches)?{?
????document.body.classList.add('dark');?
??}?else?{?
????document.body.classList.remove('dark');??
??}?
});

那么,针对不支持 CSS 变量的 IE 浏览器怎么办呢?不做兼容性处理的话那页面可能就是一团糟了。所以我们需要针对不兼容的浏览器做一些兜底处理,这里我们可以在 webpack 等构建工具中借助 post-css 的 postcss-css-variables (https://www.npmjs.com/package/postcss-css-variables) 插件来自动解析 CSS 变量对应的色值,并在原始 CSS 定义之上添加一条新的 CSS 样式,做到对不支持 CSS 变量浏览器的兼容。

代码语言:javascript
复制
//?根目录?postcss.config.js?
module.exports?=?{?
??plugins:?{?
????"postcss-css-variables":?{?
??????preserve:?true,?//?保留?var()?定义?
??????preserveInjectedVariables:?false,?//?去除其他模块的重复变量?
??????variables:?require("./page.json"),?//?CSS?变量,可以支持多个?
????}?
??}?
};

现在的 Web、App 项目大都引用第三方开源组件库,组件库一般会使用 Sass、Less 等 CSS 预处理器定义颜色变量作为组件的基础色值,并单独抽离为配置文件。所以,项目使用组件库时可以根据修改基础色值来自定义主题。那么针对项目的 深色模式适配方案也一样,主要分为三步:

  1. 组件库深浅色主题 适配
  2. 项目中 深浅色的 颜色适配
  3. 完成 CSS 变量到页面的注入

上面的都是 利用 变量,去控制样式。

sass变量与css变量处理

代码语言:javascript
复制
$var-element:'--';
//?sass?variable?map?
$colors:?(
??color-black:?#FFBB00
);

//?loop?over?each?name,?color
:root?{
??//?each?item?in?color?map
??@each?$name,?$color?in?$colors?{
????#{$var-element}#{$name}:?#{$color};
??}
}

参考文章:

深色模式适配指南?https://www.zoo.team/article/dark-theme

转载本站文章《DarkMode(2):深色模式解决方案——css颜色变量实现Dark Mode》, 请注明出处:https://www.zhoulujun.cn/html/webfront/style/darkMode/8558.html

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CSS预处理直接生成多套主题样式
  • webpack loader?modifyVars 生成多套样式
  • 媒体查询与css变量实现
    • CSS 的媒体查询
      • CSS 变量 + 媒体查询
      • sass变量与css变量处理
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
      http://www.vxiaotou.com