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