30天挑戰:「使用SCSS搭配Vue實作dark mode」技術記錄
總結
在不使用其他框架或 library 的情況下,僅透過 SCSS 與 Vue 來實作網頁的 dark mode
成品:https://tzynwang.github.io/ac_assignment_3F_ALPHA-Shop/ 原始碼:https://github.com/tzynwang/ac_assignment_3F_ALPHA-Shop
環境
Vue.js: 2.X
os: Windows_NT 10.0.18363 win32 x64
前言
結構較複雜的專案不適合僅使用<input type="checkbox">
搭配filter: hue-rotate() invert();
來實作 dark mode 需求,且在設計師有指定 dark mode 色票時,還是引入 JavaScript 來協助處理 dark mode 較為輕鬆
純 CSS 的 dark mode 相關技巧可參考:
- (YouTube) Full Dark Mode with only 1 CSS PROPERTY?!
- (YouTube) Pure CSS3 Dark Mode Effects For Website | CSS Only Night mode
正篇開始
SCSS
- 僅有需要在 dark mode 變色的顏色變數才須設定兩套值;範例中的
--primary-pink
因設計師並不打算在 dark mode 進行變色,故僅在html {...}
中出現,不須於html[data-theme="dark"] {...}
再設定一次 - 開發時可先將專案 body 中的
color
與background
都設定為最終成品不會使用到的顏色,方便一眼確認還有哪些部位沒有上色 - 版面配置多使用
padding
而非margin
,才方便滿版上色 - 使用
var()
進行顏色設定background-color: var(--white); color: var(--dark);
HTML
- 因搭配 Vue 進行操作,故在 light/dark mode 切換時需要更換圖片的部位皆須搭配
v-bind:src
,比如<img :src="navMenuIcon">
- 使用
<input type="checkbox">
搭配v-model
讀取 checkbox 的勾選狀態:<input type="checkbox" id="darkModeSwitch" v-model="darkMode">
Vue
darkMode
預設為false
- 使用
watch
監看darkMode
的值,一旦更動後,就根據darkMode
為 true 或 false 修改data-theme
(與 CSS 中的var()
變數們連動)與圖示的src
- 也可對
<input type="checkbox">
綁定@change="darkModeMethod($event)
,並透過methods
來切換為 dark mode(以下方式就不需對 input 綁 v-model):methods: { darkModeMethod (event) { if (event.target.checked) { document.documentElement.setAttribute('data-theme', 'dark') this.navLogoSrc = './images/logo-dark.svg' this.navSearchIcon = './images/icon-nav-search-dark.svg' this.navChartIcon = './images/icon-nav-chart-dark.svg' this.navModeIcon = './images/icon-nav-to-light-mode.svg' this.navMenuIcon = './images/icon-nav-menu-dark.svg' this.footerFbIcon = './images/icon-footer-fb-dark.svg' this.footerIGIcon = './images/icon-footer-ig-dark.svg' this.footerTelIcon = './images/icon-footer-tel-dark.svg' } else { document.documentElement.setAttribute('data-theme', '') this.navLogoSrc = './images/logo.svg' this.navSearchIcon = './images/icon-nav-search.svg' this.navChartIcon = './images/icon-nav-chart.svg' this.navModeIcon = './images/icon-nav-to-dark-mode.svg' this.navMenuIcon = './images/icon-nav-menu.svg' this.footerFbIcon = './images/icon-footer-fb.svg' this.footerIGIcon = './images/icon-footer-ig.svg' this.footerTelIcon = './images/icon-footer-tel.svg' } } }