前言
自上一篇文章後,就很少上來發表文章了,一方面是工作到家就有點累了,更別說沒有想到什麼適合寫的主題。剛好前幾天有個 Issue 希望我研究如何在 Angular 中快速的切換預設 / 暗色主題,也就是所謂的開關燈模式囉。
環境建置
- 建立出一個 Angualr 8 版本的空白專案
- 引入 Bootstrap 4
- 引入 Angular Material
探索
稍微了解情況後便立即開始展開網路上的搜尋,初步的整理出了以下兩種方案:
- 透過添加 / 移除
className
的方式切換主題 - 透過設置
angular.json
使其打包出兩份不同的主題 CSS ,並且將其動態引入
先破梗,兩種方案都有優缺點,端看團隊的情況能接受哪一種方案。最後我們團隊是採用第二種方案,因為這對我們來說,能避開最多可預見的問題。
實作
方案一
透過異動 className
達成切換主題的方式可以參考這篇文章做一些微調即可。
嘗試過後覺得不太適合我們,理由如下:
- 兩種主題打包後的單支 CSS 檔案太大了
- 由於是在最外層的標籤套上特定的
className
來切換主題,以我們專案來說會出現 CSS 權重問題造成跑版。- 而如果要解決這個問題,則需要到作為基底的 lib 內調整
Bootstrap 4
&Angular Material
等相關的 SCSS ,評估後覺得這個不是目前最佳解,暫時跳過。
- 而如果要解決這個問題,則需要到作為基底的 lib 內調整
方案二
做法如下:
- 建立兩份主題,如:
default-theme.scss
、dark-theme.scss
- 調整
angular.json
- 調整
styles
區塊配置- 設定
input
、bundleName
、inject
屬性input
- 要載入的 SCSS 路徑bundleName
- 獨立打包的檔案名稱inject
- 是否自動載入至index.html
- 設定
- 調整
configurations
的outputHashing
配置- 將其設定為
bundles
,確保打包後的 CSS 檔案名稱不會被加上 hash
- 將其設定為
- 調整
build
內的options
區塊配置,加入extractCss
屬性,設置為true
- 調整
- 新增
CSSLoaderService
用來動態引入指定的 CSS - 調整
index.html
,使其預設載入default-theme.scss
範例:GitHub
成果 Gif 圖
結論
透過方案二的做法,能有效的控制 CSS 大小,不會因為兩種主題而使 CSS 檔案膨脹,而這個做法也相當的簡單暴力。
甚至可以繞過很多不好處理的問題,像是 SCSS 內的變數宣告順序、又或者是多了 !default
的 SCSS 變數,方案二並非方案一是將全部 SCSS 都打包再一起成為 CSS ,所以會讓情況單純很多。
當然方案二也不是完全沒有缺點的,像是:
- 取消掉 hash 後可能需要處理 CSS 被快取住的問題 (待驗證)
- 如果單個主題 CSS 本身就有點分量,那麼切換時可能會有點延遲,這時需要透過 viewblock 等手段提升使用者體驗。