CSS Variables

開始把 Sass/Scss 趕盡殺絕

起源

因為大家都在用 sass/scss 寫樣式了,而且也真的方便許多,所以 CSS 學習這些優點開始改造,而本篇要談的便是變數系統。

用法

先來看看 scss variables 是如何使用的:

// scss 變數定義
$color-primary: blue;
$prefix: 'blueplanet'

.primary-text {
    // scss 變數使用
    color: $color-primary;
}

/*
scss 變數轉換成為字串使用方式
    會輸出成
    .blueplanet-button {
        color: red;
    }  
*/
.#{$prefix}-button {
    color: red;
}

現在來看看 CSS Variables 是如何使用的:

:root {
    --color: red;
}

.primary-text {
    color: var(--color);
}

首先使用 -- 定義名稱與內容,要使用時再加上 var() 把變數包起來即可。

注意,這裡不一定要使用 :root ,只是通常會先在根目錄定義變成全局都可以使用比較方便。詳細規則如下說明。

規則

-- 開頭做定義

如剛才的範例,要定義一個 CSS 變數,會先使用 -- 開頭做定義。

變數名稱區分大小寫

名稱針對大小寫是敏感的,請確保名稱的大小寫完全一致。

要使用變數時,在「值」的地方,使用 var() 把變數包起來

請注意,var() 僅能使用在「值」,不能使用在屬性、selector 名稱等其他地方。

/* 定義在 root 裡,是方便全局都可使用 */
:root {
    --color: red;
    --width: 768px;
}

/* 正確使用方式 */
.primary-text {
    color: var(--color);
}

/* 以下都是錯誤方式 */

.primary-var(--color) {
    color: red;
}

.primary-text {
    var(--color): red;
}

也就是說,CSS Variables 目前功能還沒辦法跟 SASS/SCSS 相提並論,但已經算很好用了。

CSS 變數具有繼承的概念、有區域性(Scoping)、且可重複定義。

如果沒有額外定義,CSS 變數將會一直繼承到子元素裡。假設我們現在有:

<div class="parent">
    <div class="child-1">Child</div>
    <div class="child-2">Child</div>
</div>
:root {
    /* 
        如果是定義在個別的 selector 裡,
        變數就只能在該 selector 裡使用。
        在 root 則是全部 selector 都能使用
    */
    --color: red;
}

.parent {
    color: var(--color);
}

.child-1 {
    color: var(--color);
}

.child-2 {
    --color: green;
    color: var(--color);
}

在此範例中,我們在 .child-2 重新定義了 --color 變數,所以再次指定屬性時,文字顏色便會改變,而 .child-1 指定屬性時,還是一樣的顏色。

一定要再次針對該屬性給值,否則是不會改變的喔!

例如 .child-2 如果沒有再寫一次 color: var(--color);

.child-2 的文字依舊會是紅色的!

請注意,並不是改變變數,就會直接套用在外觀上,還得再應用一次!

應用 var() 時,如果取不到 CSS 變數,可以給予預設值(fallback)

其實 var() 可以給予兩個變數,第一個為想取得的變數,第二個為預設值,而預設值裡也可用變數。

:root {
    --default-color: red;
    --color: green;
}

.demo {
    /* 如果取不到 --color,則會是橘色 */
    color: var(--color, orange);
}

.demo-2 {
    /* 如果取不到 --color,則會是紅色 */
    color: var(--color, var(--default-color));
}

.demo-3 {
    /* 如果取不到 --color 也取不到 --default-color,則會是紫色 */
    color: var(--color, var(--default-color, purple));
}

遇到屬性不可以使用的 var() 值時,本身視為「沒有樣式」,要先檢查是否有繼承,如果沒有繼承則會使用瀏覽器預設值

一般來說,當我們重複定義元素的 css 時,如果最後套用的屬性值是不合規定的,通常就是視為無效,會套回到次一個權重的樣式。例如:

.demo {
    color: red;
}

.demo {
    color: 16px;
}

這樣的結果,.demo 會是紅色的,後面是無效值瀏覽器會無視,直接使用前一個定義的樣式。

var() 是不一樣的,瀏覽器依舊會套用變數後的結果不會無視,造成之前定義的視為被覆蓋了,但又因為我們的變數值跟屬性是不合的,所以等同於這個 selector 完全沒有定義樣式了,依照 CSS 的規則,也就是說,要不就是使用繼承,要不就是使用預設值,例如:

:root {
    --width: 768px;
    --color: green;
}

html {
    color: red;
}

.demo {
    color: var(--color, orange);
}

.demo {
    color: var(--width);
}

可以看到,第一次定義的 demo 被瀏覽器視為覆蓋,但又因為第二次定義的值有應用但是無效的值,等於 demo 自己本身完全沒有顏色樣式了,所以只能看看上層是否有繼承下來,如果沒有就會變成預設值。

Javascript 可以控制 CSS 變數

這對於前端工程師來說變得方便極了!以往沒辦法直接改 SASS/SCSS 的變數(因為他需要經過編譯的過程),可能要透過 selector + css 的方式更改樣式,或是直接使用 style.XXX 直接改,搞到後來一團亂,如果現在可以使用 Javascript 取得變數和改變數,在樣式的管理上將會是非常方便的功能,也比較不怕改壞 CSS。

// get variable from inline style
element.style.getPropertyValue("--my-var");

// get variable from wherever
getComputedStyle(element).getPropertyValue("--my-var");

// set variable on inline style
element.style.setProperty("--my-var", jsVar + 4);

小結

原生 CSS 取代 SASS/SCSS 的開始,且目前主流瀏覽器都已支援,少了一層依賴,就少了一層風險,建議大家可以開始應用在專案/產品上了。

作業

請試著規劃出一個主題色變數檔案,方便切換色系。

參考連結

Last updated