CSS 自定義屬性指北

Grewer發表於2022-05-10

前言

在現代瀏覽器中, 我們會經常看到這樣的屬性:

element {
  --main-bg-color: brown;
}

這裡我們就來介紹一下他, 並提供一些相關的說明

簡介

自定義屬性(有時候也被稱作CSS變數或者級聯變數)是由CSS作者定義的,它包含的值可以在整個文件中重複使用。由自定義屬性標記設定值(比如: --main-color: black;),由var() 函式來獲取值(比如: color: var(--main-color);)

宣告

宣告一個自定義屬性,屬性名需要以兩個減號(--)開始,屬性值則可以是任何有效的CSS值。
如前言中的 --main-bg-color 屬性

通常的最佳實踐是定義在根偽類 :root 下,這樣就可以在HTML文件的任何地方訪問到它了:

/*:root 選擇器匹配文件根元素。*/
/*在 HTML 中,根元素始終是 html 元素。*/
/*也就是說:root 表示的是根元素*/

:root {
  --main-bg-color: brown;
}
注意:自定義屬性名是大小寫敏感的,--my-color 和 --My-color 會被認為是兩個不同的自定義屬性。
同時不能包含$,[,^,(,%等字元,普通字元侷限在只要是“數字[0-9]”“字母[a-zA-Z]”“下劃線_”和“短橫線-”這些組合,但是可以是中文,日文或者韓文,例如
body {
  --深藍: #369;
  background-color: var(--深藍);
}

使用

element {
  background-color: var(--main-bg-color);
}

這些自定義屬性,僅當需要的時候才會計算,而並不會按其他規則進行儲存。比如,你不能為元素設定一個屬性,然後讓它從兄弟或旁支子孫規則上獲取值。屬性僅用於匹配當前選擇器及其子孫,這和通常的CSS是一樣的。

預設值

用 var() 函式可以定義多個備用值(fallback value),當給定值未定義時將會用備用值替換。

/*如果提供了第二個引數,則表示備用值,當自定義屬性值無效時生效。第二個引數可以巢狀,但是不能繼續平鋪展開下去了,例如:*/
.two {
  color: var(--my-var, red); /* Red if --my-var is not defined */
}

.three {
    background-color: var(--my-var, var(--my-background, pink)); /* pink if --my-var and --my-background are not defined */
}

.three {
    background-color: var(--my-var, --my-background, pink); /* Invalid: "--my-background, pink" */
}

第二個例子展示瞭如何處理一個以上的 fallback。該技術可能會導致效能問題,因為它花了更多的時間在處理這些變數上。

在 js 中操作

在 JavaScript 中獲取或者修改 CSS 變數和操作普通 CSS 屬性是一樣的:

// 獲取一個 Dom 節點上的 CSS 變數
element.style.getPropertyValue("--my-var");

// 獲取任意 Dom 節點上的 CSS 變數
getComputedStyle(element).getPropertyValue("--my-var");

// 修改一個 Dom 節點上的 CSS 變數
element.style.setProperty("--my-var", jsVar + 4);

CSS變數的空格尾隨特性

body {
  --size: 20;   
  font-size: var(--size)px;
}

此處font-size:var(--size)px等同於font-size:20 px,注意,20後面有個空格,所以,這裡的font-size使用的是<body>元素預設的大小。

使用場景

簡單的實現一種進度條:

外面有一層背景層,然後裡面有進度條,還有進度值。

在過去,會使用兩層div元素,然後JS去改變裡面有顏色條條的寬度,同時設定進度值。

<label>圖片1:</label>
<div class="bar" style="--percent: 60;"></div>
<label>圖片2:</label>
<div class="bar" style="--percent: 40;"></div>
<label>圖片3:</label>
<div class="bar" style="--percent: 20;"></div>
.bar {
    height: 20px; width: 300px;
    background-color: #f5f5f5;
}
.bar::before {
    display: block;
    counter-reset: progress var(--percent);
    content: counter(progress) '%\2002';
    width: calc(1% * var(--percent));
    color: #fff;
    background-color: #2486ff;
    text-align: right;
    white-space: nowrap;
    overflow: hidden;
}

可以看到,我們只需要一層div標籤,DOM層級簡單了,然後,需要修改的HTML變化項僅僅是一個--percent自定義屬性而已。

更多場景可參考此文章: https://www.zhangxinxu.com/wo...

擴充套件

我們可以通過 @property 來擴充套件 CSS 變數:

他的語法:

@property --property-name {
  syntax: '<color>';
  inherits: false;
  initial-value: #c0ffee;
}

@property 規則中 syntaxinherits 描述符是必需的; 如果其中任何一項缺失, 整條規則都將失效並且會被忽略。

initial-value 描述符僅在 syntax 描述符為通用 syntax 定義時是可選的,否則 initial-value 也是必需的——如果此時該描述符缺失,整條規則都將失效且被忽略。

當然我們也可以使用 js 來建立:

window.CSS.registerProperty({
  name: '--my-color',
  syntax: '<color>',
  inherits: false,
  initialValue: '#c0ffee',
});

他的作用, 很多情況是為了實現了一些以往無法簡單實現的動畫效果

詳細可以參考此文章, 裡面舉了幾個例子: https://juejin.cn/post/695120...

相容性

目前 css 變數的相容是最低 Chrome49:

在 CSS 中我們也可以進行相容性處理:

.selector: {}
@supports ( (--a: 0)) {
  /* supported */ 
    .selector: {}
}
@supports ( not (--a: 0)) {
  /* not supported */
    .selector: {}
}

在 js 中也可以進行對應判斷

const isSupported =
    window.CSS &&
    window.CSS.supports &&
    window.CSS.supports('--a', 0);

@property 還只是一個實驗中的屬性, 他的相容要求是十分高的:

polyfill

https://github.com/jhildenbid...

使用此相容直接可以達到的相容:
Chrome 19+
Edge 12+
Firefox 6+
IE 9+
Safari 6+

目前的情況

less/sass

在大多數的專案中, 是使用 less/sass/scss 的, 但是在這幾種 css 預處理工具中已經有了變數的功能, 如果再加上 CSS 原生變數一起使用的話, 就會顯得很冗餘

針對這些前處理器, 我們就使用原生 css 變數替代原有的變數, 其他的仍舊保持不變

css in js

在 root 中定義完畢基礎 CSS 後, 就可以在 js 中使用了, 在這種框架有他是有很大定發揮空間的

原子css

現在常用的一種原子化 CSS 框架: tailwindcss

在這種框架中, 內部就廣泛使用CSS變數, 所以如果你能使用 Tailwind, 你就能使用 CSS變數

總結

CSS 變數這一功能, 現在的瀏覽器支援度已經足夠了, 同時針對現有的 CSS 多種前處理器, 有了一定的適配度, 如果有使用的打算, 可以嘗試引入了

當然現在沒有一個比較全面的解決方案, 想要再觀望下也是沒問題的

引用

相關文章