CSS變量(自定義屬性)實踐指南

轉載請註明出處:葡萄城官網,葡萄城爲開發者提供專業的開發工具、解決方案和服務,賦能開發者。css


Sass和Less這樣的預處理器,讓咱們的CSS代碼保持良好的結構和可維護性。像變量、混合(mixins)、循環控制等特性,加強了動態編寫CSS的能力,從而減小重複代碼,也加快了咱們開發速度。html

近年來,一些動態特性開始做爲規範的一部分,出如今CSS語言中。CSS變量(CSS variables),或者用它的官方稱謂,叫做自定義屬性(custom properties),已經可用,而且有很是棒的瀏覽器支持,而CSS mixins也正在取得進展。前端

在本文,你將學會如何使用CSS變量,並把它集成到你的CSS開發流程中,讓你的樣式表更好維護,且減小重複。git

讓咱們如今就開始吧!編程

什麼是CSS變量?

若是你曾使用過某種編程語言,那麼你已經很熟悉變量這個概念了。變量用於存儲和更新你的程序所須要的值,以便使它運行。瀏覽器

例如,考慮下面的JavaScript代碼緩存

let number1 = 2;
    let number2 = 3;
    let total = number1 + number2;
    console.log(total); // 5
    number1 = 4;               
    total = number1 + number2;
    console.log(total); // 7

nubmer1和 number2是兩個變量,分別存儲着數字2和3。編程語言

total一樣是變量,存儲着number1與number2之和。在這裏它的值就是5。你能夠動態地修改變量裏的值,並在程序中使用它們。在上面的代碼中,我把number1的值更新爲4,而後再進行求和。使用相同的變量,這個時候total裏存儲的值就是5,而再也不是7了。ide

使用變量的妙處在於,它可讓你在一個地方存儲值,而且讓你在後面能以各類理由去更新它。在程序中,你不須要爲不一樣的值再添加額外的字符表示:任何值的更新都發生在同一個地方。正如,在你定義的變量上。svg

CSS在很大程度上是一種聲明式的語言,而缺乏動態能力。你也許會認爲,讓CSS擁有變量,幾乎讓上面的說法自相矛盾。若是前端開發僅僅是關於文字遊戲,那能夠這麼說。幸運的是,Web的編程語言很像生活中的語言,它們會隨着周圍環境和實踐須要而不斷進化與適應。CSS也一樣如此。

簡單的說,變量已經成爲CSS世界中激動人心的事實,而且你即將親自看到,對於這個厲害的新技術,學習和使用起來都很是直觀。

使用CSS變量有什麼好處?

使用CSS變量的好處,跟在其餘編程語言中使用變量的好處沒什麼大的區別。

W3C 規範是這樣描述這一點的

使用CSS變量,給看似隨機的值加上富有信息的名字,從而使得大文件更容易閱讀和編輯,更少出錯。由於,你只須要在自定義屬性中改變一次值,全部應用了這個變量的地方都會自動跟着一塊兒改變。

換句話說,經過給變量起一個對你來講在項目中有意義的名字,你能更容易的管理和維護你的代碼。例如,當你爲項目中的主色調設置一個變量名--primary-color,那麼你後面再修改這個主色調時,只須要改動一處,而不須要在不一樣位置的多個CSS文件中去手動修改屢次值。

CSS變量和預處理器中的變量有什麼不一樣?

你可能已經在CSS預處理器中嘗試過使用變量而帶來的好處了,好比Sass和Less。

預處理器讓你能設置變量,以及在函數、循環、數學計算等等地方中使用它們。這是否意味着CSS變量已經可有可無了呢?

那可未必,主要是由於,CSS變量與預處理器中的變量實際上是不一樣的東西。

這些不一樣基於一個事實:CSS變量是瀏覽器中直接可用的CSS屬性,而預處理中的變量是用於編譯成常規的CSS代碼,瀏覽器其實對它們一無所知。

這意味着,你能夠在樣式表中,在內聯樣式中,在SVG的標籤中直接更新CSS變量,甚至能夠在運行時用JavaScript直接修改它。而你是沒法對預處理器中的變量作上面這些操做的。CSS變量開啓了一個充滿可能性的新世界大門。

不是說你必需要在二者間作出選擇:沒有什麼東西限制你,你能夠同時使用CSS變量和預處理變量,並享有它們各自帶來的巨大好處。

CSS變量:語法

雖然本文爲了簡潔,我使用了CSS變量(CSS variables)這個稱呼,但官方的規範把它們稱做做爲級聯變量的CSS自定義屬性(CSS custom properties for cascading variables)。CSS自定義屬性(CSS custom property)的部分看起來像這樣:

--my-cool-background: #73a4f4;

在自定義屬性前添加雙橫線前綴,而後像給普通CSS設值同樣,給自定義屬性設值。在上面的代碼中,我給一個叫作--my-cool-backgroud的自定義屬性設置了一個顏色值。

級聯變量(cascading variable) 的部分,由經過val()來使用你的自定義屬性組成,開起來像這樣:

var(--my-cool-background);

自定義屬性做用於CSS選擇器中,val()可被當成一個真正的CSS屬性同樣使用。

:root {
        --my-cool-background: #73a4f4;
    }
     
    /* CSS文件的其餘部分 */
    #foo {
        background-color: var(--my-cool-background);
    }

上面的代碼片斷把--my-cool-background這個自定義屬性的做用域定義在:root這個僞類中,這讓該自定義屬性能被全局訪問到(即在<html>標籤內部的任何地方)。而後,使用val()函數把ID爲foo的容器的background-color設置爲自定義屬性的值,這時該容器就有了淺藍的背景色。

這還沒完。你能夠用一樣的淺藍色,給多個HTML標籤的多種能夠設置顏色值的地方設值,好比設置它們的color和border-color。方法很簡單,就是經過var(--my-cool-background)拿到自定義屬性的值,而後給合適的CSS屬性設置上去。(固然,在事情變得複雜以前,我建議思考一下你的CSS變量命名規範):

p {
        color: var(--my-cool-background);
    }

示例1代碼,可點擊查看。

你還能夠從經過利用CSS變量得到另外一個CSS變量的值。例如:

--top-color: orange;
    --bottom-color: yellow;
    --my-gradient: linear-gradient(var(--top-color), var(--bottom-color));

上面的代碼建立了一個--my-gradient變量,是一個漸變樣式,它的值被設爲--top-color的值和--bottom-color的值組合的結果。如今,你能夠在任什麼時候候修改你的漸變樣式,僅僅是修改變量的值就能夠了,而再也不須要在樣式表裏滿文件地去找用到這個漸變樣式地方。

示例2代碼。

最後,你能夠在CSS變量中加入一個或多個備用值(fallback value/s),例如:

var(--main-color, #333);

上面的代碼中,#333是一個備用值。當自定義屬性值無效或未指定(unset)時,若是這時也沒有指定備用值,那麼被繼承的(inherited)屬性值將會被使用。

CSS變量是區分大小寫的

與普通CSS屬性不一樣,CSS變量是區分大小寫的。

例如,var(--foo)和var(--FOO)是在求兩個不一樣的自定義屬性值,分別是--foo和--FOO的。

CSS變量受級聯關係影響

和普通CSS屬性同樣,CSS變量是可繼承的。例如,咱們定義了一個屬性,值爲blue:  

:root {
        --main-color: blue;
    }

當你給任意在<html>標籤裏的元素指定--main-color變量時,它們都會繼承到blue這個值。

當你在另外一個元素裏,爲改自定義屬性設置了一個新值時,那麼全部該元素的子元素都會繼承那個新值。例如:  

:root {
        --main-color: blue;
    }
    .alert {
        --main-color: red;
    }
    p {
        color: var(--main-color);
    }
    <--! HTML -->
    <html>
      <head>
        <!-- head code here -->
      </head>
     
      <body>
        <div>
          <p>blue 的段落</p>
          <div class="alert">
            <p>red 的段落</p>
          </div>
        </div>
      </body>
    </html>

在上面的標籤中,第一個p段落會繼承到全局的--main-color值,它是藍色。

在div標籤中擁有.alert類的段落會是紅色,由於它的值繼承自局部做用域裏的--main-color。

示例3代碼

知道目前這些規則差很少夠了。讓咱們開始寫代碼吧!

如何在SVG中使用CSS變量

CSS變量和SVG配合得很好。你可使用CSS變量去修改SVG中的樣式,以及和呈現相關的屬性。

舉個例子,假設你想讓你的SVG圖標能跟隨其所在父容器而擁有不一樣的顏色。你能夠把CSS變量的做用域限定在父容器中,而後給變量設置想要的顏色,那麼裏面的圖標就會繼承父容器的顏色值。下面是相關代碼:

/* inline SVG symbol for the icon */
    <svg>
      <symbol id="close-icon" viewbox="0 0 200 200">
        <circle cx="96" cy="96" r="88" fill="none" stroke="var(--icon-color)" stroke-width="15" />
        <text x="100" y="160" fill="var(--icon-color)" text-anchor="middle" style="font-size:250px;">x</text>
      </symbol>
    </svg>
     
    /* first instance of the icon */
    <svg>
      <use xlink:href="#close-icon" />
    </svg>

上面的代碼使用了<symbol>標籤,它讓你建立一SVG圖形的不可見的版本。而後再使用<use>標籤生成一個可見的副本。這種方法可讓你根據本身的喜愛建立任意多個自定義的圖標,也就是經過它的ID(#close-icon)指向那個<symbol>。這比一遍又一遍地寫重複的代碼建立圖形更加簡便。若是你想提升這方便的技術,Massimo Cassandro在他的Build Your Own SVG Icons中提供了一個快速教程。

注意到SVG symbol中,circle元素裏的stroke屬性和text元素裏的fill屬性:它們都使用了CSS變量,這裏是--icon-color。它被定義在:rootCSS文件的選擇器中,像這樣:  

:root {
        --icon-color: black;
    }

這是當前圖標看起來的樣子:
圖片描述

這時,若是你把一樣的SVG圖標放在不一樣的父容器中,而且在父容器上,給你的CSS變量設置各自的局部值,那麼你就會獲得不一樣顏色的圖標,而且不用給你的樣式表添加多餘的規則。這很酷!

爲了展現這一點,咱們把一樣的圖標放在一個有.success類的div裏:

<!-- html -->
    <div class="success">
        <svg>
            <use xlink:href="#close-icon" />
        </svg>
    </div>

如今,讓--icon-color變量局部化,即把它放在.success中,並設置一個green值。咱們來看看發生的變化:

/* css */
    .success {
        --icon-color: green;
    }

這個圖標的顏色就變成了綠色:  
圖片描述
  

來看看一個完整的示例吧: 示例4代碼。

如何在@keyframes中使用CSS變量

CSS變量能夠在CSS動畫中使用,便可用於常規HTML元素,也能夠用於內聯的SVG。只須要記得,你得知道讓什麼元素動,把它視爲目標元素,而後建立對該目標元素的選擇器,在選擇器的做用範圍中定義你的CSS變量,而後,使用val()獲取這些變量,把它們設置到@keyframes代碼塊中。

例如,讓SVG中.bubble類裏面的<ellipse>元素動起來,你的CSS可能會看起來像這樣:

.bubble {
      --direction-y: 30px;
      --transparency: 0;
      animation: bubbling 3s forwards infinite;
    }
     
    @keyframes bubbling {
      0% {
        transform: translatey(var(--direction-y));
        opacity: var(--transparency);
      }
      40% {
        opacity: calc(var(--transparency) + 0.2);
      }
      70% {
        opacity: calc(var(--transparency) + 0.1);
      }
      100% {
        opacity: var(--transparency);
      }
    }

注意到這是如何藉助CSS的calc(),並用var()函數進行計算的。它們加強了你代碼的靈活性。

這個例子簡潔的地方在於,利用CSS屬性,你能夠簡單的修改相應選擇器裏變量值而調整動畫,而不須要挨個去查找@keyframes裏的屬性了。

這裏有個完整的例子供你體驗:示例5代碼。  

如何經過JavaScript操做CSS變量

另外一個超級酷的事情就是,你能夠直接經過JavaScript代碼訪問CSS變量。

假設在你的CSS文件中,有一個叫作--left-pos的變量,做用在.sidebar選擇器中,值爲100px:

.sidebar {
        --left-pos: 100px;
    }

那麼,經過JavaScript獲取--left-pos值,會像下面這樣:

// 緩存你即將操縱的元素
    const sidebarElement = document.querySelector('.sidebar');
     
    // 緩存sidebarElement的樣式於cssStyles中
    const cssStyles = getComputedStyle(sidebarElement);
     
    // 獲取 --left-pos CSS變量的值
    const cssVal = String(cssStyles.getPropertyValue('--left-pos')).trim();
     
    // 將CSS 變量的值打印到控制檯: 100px
    console.log(cssVal);

若是想經過JavaScript設置CSS變量的值,你能夠像這樣:

sidebarElement.style.setProperty('--left-pos', '200px');

上面的代碼將sidebar元素中--left-pos變量的值設置爲200px。

請看看CodePen中的以下示例,你能夠交互式地點擊側邊欄,修改blend mode屬性和背景色。這些實現只用到了CSS變量和JavaScript。

示例6代碼。

CSS變量的瀏覽器支持

除了IE11(它不支持CSS變量),全部主流瀏覽器都對CSS變量有全面地支持。

對於不支持CSS變量的瀏覽器,一個變通的方案是使用具備虛擬查詢條件(dummy conditional query)的@supports代碼塊:

section {
        color: gray;
    }
     
    @supports(--css: variables) {
        section {
            --my-color: blue;
            color: var(--my-color, 'blue');
        }
    }

考慮到@supports在IE/Edge裏也起做用,上面的方法是可行的。若是你在val()函數中使用了備用值,那麼你的代碼將更加可靠,它能在兼容性很差的瀏覽器中實現優雅降級。

對於上面的代碼,在Chrome和其餘支持CSS變量的瀏覽器中,<section>標籤裏的文本將是藍色:
圖片描述

在IE11中,因爲它不支持CSS變量,頁面將顯示灰色文本:
圖片描述
  

能夠查看在線的示例7代碼

此方法的一個缺點是,若是你大量使用CSS變量,而那些不支持CSS變量的瀏覽器在你的項目中有很高的適配優先級,那麼相應的代碼會變得很複雜,對於維護來講,甚至是噩夢。

在這種狀況下,你能夠選擇使用帶有cssnext的PostCSS,它能讓你在CSS代碼中使用最新的特性,而且讓本來不支持這些屬性的瀏覽器,也能運行這些代碼(有點像JavaScript轉換器作的事情)。

備註:這裏可下載本文全部示列代碼


本文是由葡萄城技術開發團隊發佈,轉載請註明出處:葡萄城官網

本中提到的CSS變量已經在SpreadJSWijmo中獲得應用,

  1. 瞭解可嵌入您系統的在線 Excel,請前往 SpreadJS
  2. 瞭解全面支持Angular、React和Vue的前端開發工具,請前往 WijmoJS
相關文章
相關標籤/搜索