CSS也能像元件狀態一樣響應式更新?

語言: CN / TW / HK

大家好,我是卡頌。

不知道平時在專案裡你怎麼處理 CSS 呢?

我們知道,由於原生 CSS 存在一些問題,比如:

  • 複用時容易樣式衝突
  • 沒有作用域、沒有模組化
  • 沒有程式設計能力

社群湧現出很多解決方案,比如:

  • 命名規範(比如 BEM 規範)
  • 模組規範(CSS Modules)
  • CSS 前處理器(比如 Less
  • CSS In JS
  • CSS 框架( Tailwind CSS

......

如果我們按以下三個維度評判這些方案:

CSS
CSS

會發現每個方案都有自己的優勢與短板。

比如:

  • CSS In JS 方案用 JSCSS ,擁有極高靈活性,但加大了上手難度
  • LessCSS 前處理器)可以看作 CSS 的超集,上手難度低、有一定程式設計能力,但是 CSS 自身的問題他也存在

業界常見做法是:同時使用 BEM 規範(解決命名衝突問題)+ CSS 前處理器。

進擊的Vue CSS解決方案

我們用這三個維度分析下 VueSFC (Single-File-Component,單檔案元件):

<template>
  <p>xxx</p>
</template>

<script>
  // ...
</script>

<style scoped>
  p {
    color: #0f0;
  }
</style>
  • 上手難度:樣式在 <style> 標籤內書寫,與原生 CSS 別無二致,上手簡單,符合直覺
  • 能力: scoped 標識提供了 模組化 能力
  • 靈活性:可以使用各種前處理器,有一定靈活性

可以看到, Vue SFC 採用的是一種各方面沒有明顯短板,區域性很突出(上手難度低)的 CSS 方案。

隨著 Vue 3.2釋出, Vue SFC 中的 CSS 屬性獲得了 響應式更新能力 ,使其靈活性大大提升。

響應式CSS屬性

對於如下 Vue SFC

<template>
  <div class="text">hello</div>
</template>

<script>
export default {
  data() {
    return {
      color: 'red'
    }
  }
}
</script>

<style>
.text {
  color: v-bind(color);
}
</style>

<script> 標籤內定義了狀態 color = 'red'

.text 使用 v-bindcolor 屬性繫結該狀態。效果如下:

為了驗證響應式更新能力, 為 div 增加點選事件:

<div class="text" @click="color= color === 'red' ? 'green' : 'red'">hello</div>

點選後會讓 color 狀態在 redgreen 間切換。可以看到,頁面樣式也會同步變化:

Demo地址

不僅是 color ,你可以為任何 CSS 屬性繫結狀態。

那麼這個特性是如何實現的呢?

實現原理

每個使用 v-bind 繫結到 CSS 屬性的狀態對應一個 CSS 變數,該 CSS 變數會作為 style 屬性賦值給元件最外層 DOM

在我們的例子中:

.text {
  color: v-bind(color);
}

其中 v-bind(color) 會成為 CSS 變數:

並作為 style 屬性賦值給 div

.text 經過編譯會使用該 CSS 變數:

.text {
  // 編譯前
  /* color: v-bind(color); */
  // 編譯後
  color: var(--469af010-color);
}

當顏色變化後, CSS 變數的值隨之變化:

所以,要使用這個特性需要目標瀏覽器支援 CSS 變數。

Vue3 放棄 IE 這可是說到做到的。

總結

Vue 官方稱該特性為 State-Driven Dynamic CSS

經過這波操作, Vue SFCCSS 靈活性有了很大提高。

並且,有了 v-bind 這個開頭,相信未來會出現更多與 響應式更新 掛鉤的 自定義CSS指令

之前的自定義指令都是執行時的,以後的指令可能會是基於 AST 的編譯時了。這種轉變,你接受嗎?