DarkMode(2):深色模式解決方案——css顏色變量實現Dark Mode

暗黑模式實現,最初的設計,就是參考之前的主題模式。所謂多套主題/配色/皮膚,就是我們很常見的換膚功能。換膚簡單的實現就是更換 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

方法還處于 W3C 草案規范:https://caniuse.com/?search=prefers-color-scheme

CSS 變量CSS variables、CSS custom properties

CSS 變量除了 IE,其余各大瀏覽器都支持的比較好:https://caniuse.com/?search=variables

二者配合就可以實現頁面主題跟隨系統自動切換深淺模式 。

CSS 的媒體查詢

prefers-color-scheme?是一種用于檢測用戶是否有將系統的主題色設置為亮色或者暗色的 CSS 媒體特性。 利用其設置不同主題模式下的 CSS 樣式,瀏覽器會自動根據當前系統主題加載對應的 CSS 樣式。light 適配淺色主題,dark 適配深色主題,no-preference 表示獲取不到主題時的適配方案。

CSS

@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 標簽

<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 生效。

.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。

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 變量瀏覽器的兼容。

//?根目錄?postcss.config.js?

module.exports?=?{?

??plugins:?{?

????"postcss-css-variables":?{?

??????preserve:?true,?//?保留?var()?定義?

??????preserveInjectedVariables:?false,?//?去除其他模塊的重復變量?

??????variables:?require("./page.json"),?//?CSS?變量,可以支持多個?

????}?

??}?

};

現在的 Web、App 項目大都引用第三方開源組件庫,組件庫一般會使用 Sass、Less 等 CSS 預處理器定義顏色變量作為組件的基礎色值,并單獨抽離為配置文件。所以,項目使用組件庫時可以根據修改基礎色值來自定義主題。那么針對項目的 深色模式適配方案也一樣,主要分為三步:

組件庫深淺色主題 適配

項目中 深淺色的 顏色適配

完成 CSS 變量到頁面的注入

上面的都是 利用 變量,去控制樣式。

sass變量與css變量處理

$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

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容