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

来源:https://www.cnblogs.com/powertoolsteam/archive/2018/08/29/css-variables.html
-Advertisement-
Play Games

近年來,一些動態特性開始作為規範的一部分,出現在CSS語言中。在本文,你將學會如何使用CSS變數,並把它集成到你的CSS開發流程中,讓你的樣式表更好維護,且減少重覆。 ...


本文翻譯自:https://www.sitepoint.com/practical-guide-css-variables-custom-properties/

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

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

近年來,一些動態特性開始作為規範的一部分,出現在CSS語言中。CSS變數(CSS variables),或者用它的官方稱謂,叫作自定義屬性(custom properties),已經可用,並且有非常棒的瀏覽器支持,而CSS mixins也正在取得進展。

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

讓我們現在就開始吧!

什麼是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同樣是變數,存儲著number1number2之和。在這裡它的值就是5。你可以動態地修改變數里的值,併在程式中使用它們。在上面的代碼中,我把number1的值更新為4,然後再進行求和。使用相同的變數,這個時候total里存儲的值就是5,而不再是7了。

使用變數的妙處在於,它可以讓你在一個地方存儲值,並且讓你在後面能以各種理由去更新它。在程式中,你不需要為不同的值再添加額外的字元表示:任何值的更新都發生在同一個地方。正如,在你定義的變數上

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

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

使用CSS變數有什麼好處?

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

規範是這樣描述這一點的

使用CSS變數,給看似隨機的值加上富有信息的名字,從而使得大文件更容易閱讀和編輯,更少出錯。因為,你只需要在自定義屬性中改變一次值,所有應用了這個變數的地方都會自動跟著一起改變。W3C 規範

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

CSS變數和預處理器中的變數有什麼不同?

你可能已經在CSS預處理器中嘗試過使用變數而帶來的好處了,比如SassLess

預處理器讓你能設置變數,以及在函數、迴圈、數學計算等等地方中使用它們。這是否意味著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標簽的多種可以設置顏色值的地方設值,比如設置它們的colorborder-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轉換器做的事情)。

備註:這裡可下載本文所有示列代碼

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • angularjs小練習(分別通過ng-repeat和ng-option動態生成select下拉框),  在實現上有兩種方式:其一、通過ng-repeat來實現;其二、通過ng-option來實現 ...
  • import originJsonp from 'jsonp' export default function jsonp(url, data, option) { url += (url.indexOf('?') { originJsonp(url, option, (err, data) => ... ...
  • 1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>事件冒泡-提示框</title> 7 </head> 8 <style> 9 button { 10 width: 160px; 11 ...
  • 展示: ...
  • 前言 對於vue cli的強大,使用過的人都知道,極大的幫助我們降低了vue的入門門檻 最近在看webpack4,深感知識淺薄,這兩天也一直在思考cli的配置,藉助一些別人的實踐,嘗試自己搭建vue的項目,這裡使用webpack4版本,之前我在網上查找別人的vue項目搭建,但是都是webpack3的 ...
  • 強弱類型的語言,簡單來區分就是會不會隱式轉換數據類型, 比如最常見的數值型與字元串之間的轉換 強類型的語言 : java , .net , python等 弱類型的語言: php JavaScript等 舉個python 與 JavaScript的例子 python a = 5 b = '5' pr ...
  • angularjs通過ng-change和watch兩種方式實現對錶單輸入改變的監控 ...
  • 面試中2次被問到過這個知識點,實際開發中,應用事件委托也比較常見。JS中事件委托的實現主要依賴於 事件冒泡 。那什麼是事件冒泡?就是事件從最深的節點開始,然後逐步向上傳播事件,舉個例子:頁面上有這麼一個節點樹,div>ul>li>a;比如給最裡面的a加一個click點擊事件,那麼這個事件就會一層一層 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...