[CSS] vue 專案中 css 變數無法作用問題

最一開始,其實我是想用 js 更改 scss 變數內容來達到網站更換顏色的效果,查了一些資料之後發現,喔,這是不可行的啦。

scss 都叫 "預"處理器了,所以關於 scss 的資訊在檔案編譯成 css 的時候都會消失,也就無法再透過 javascript 去更改了。

結論: scss 沒辦法搭配 javascript 做到這種操作。
 

但是~~!這樣的效果可以考慮使用 css 的變數來完成。
 

css 變數常見的寫法之一是把變數宣告放在一個 :root 的偽元素中。

為什麼是 :root 呢?

 
主要是因為,宣告及使用 CSS 變數和宣告及使用 JS 變數一樣,是有作用範圍 (scope) 的。

若將變數宣告在某個元素的 CSS 內,只有該元素本身以及該元素的子元素、孫元素、子子孫孫們能夠使用該變數。

而 :root 這個虛擬類別 (pseudo-class) 代表 DOM 的根,

也就是 的 CSS Selector,由於它是整顆 DOM 的最高點,因此大家都可以輕易地使用掛在上面的 CSS 變數。

 
了解以上原理之後,馬上來實作一下。

<style lang="css" scoped>
:root {
  --mainColor1: rgb(27, 233, 20);
}

.header {
  background: var(--mainColor1);
}
</style>

 

然後你可能會發現,樣式沒吃到誒!!!

怎麼回事?
 
測試一下之後,會發現一切問題的癥結好像就是那個 scoped!

我們把 scoped 拿掉看看?好的,這下有樣式了!!

但是,為什麼呢???
 
 
先複習一下 scoped 的功能:

When a <style> tag has the scoped attribute, its CSS will apply to elements of the current component only.

翻譯成中文大概就是加入 scoped 屬性的 <style> tag 的樣式只會套用於當前套件。

通常會使用 scoped 是為了不汙染全域的樣式。
 
 
實測時可以發現,如果加上了 scoped,vue 在渲染之後元素會替其加上 [data-v-1c570aa7] 類似這樣的東西來達成確保樣式唯一的目的。
 
 
然而,像這樣的東西,
 

[data-v-1c570aa7]:root {
 --mainColor1: rgb(27, 233, 20);
}

 
是無法對應到實際的 :root 元素的。

也就會導致沒有樣式效果的結果。

 
ps. 原文這句的 target 我有點不知道怎麼翻: it will not target actual :root element.
 
所以講那麼多,其實解決方式也很簡單粗暴,就是拿掉 scoped。

不過要注意也可能因此造成樣式衝突就是了。
 
 
參考文章
How to control Sass Variable with javascript
css variable + sass variable = 😍
Day 3 - CSS Variables
vue中scoped的原理及慎用原因
Scoped CSS
CSS variables use in Vue