CSS自定義屬性 —— 別說你懂CSS相對單位

圖片描述

前段時間試譯了Keith J.Grant的CSS好書《CSS in Depth》,其中的第二章《Working with relative units》,書中對relative units的講解和舉例能夠說至關全面,看完以後發現本身並不太懂CSS相對單位,也但願分享給你們,因此有了這個譯文系列。(如有勘誤或翻譯建議,歡迎 Github PR ^_^javascript

《別說你懂CSS相對單位》系列譯文:css

  1. 如何更愉快地使用em
  2. 如何更愉快地使用rem
  3. 視口相關單位的應用
  4. 無單位數字和行高
  5. CSS自定義屬性 [本文]

本文對應的章節目錄:前端

  • 2.6 自定義屬性(也叫「CSS變量」)java

    • 2.6.1 動態改變自定義屬性的值
    • 2.6.2 經過JavaScript改變自定義屬性的值
    • 2.6.3 初探自定義屬性
  • 總結
譯者說
 
在今年年初,我也寫過一篇 《CSS Variables學習筆記》,裏面有更多的CSS Variables的語法解釋和實例demo,感興趣的朋友能夠看看 :)
 
本文也是《別說你懂CSS相對單位》系列的最後一篇,感謝小夥伴們的支持和建議,enjoy 🎉🎉🎉 意猶未盡的朋友們,能夠去看看Keith J.Grant的《CSS in Depth》。
 

2.6 自定義屬性(也叫「CSS變量」)

在2015年,一個你們期待已久的名爲「用做層疊式變量的自定義屬性」(Custom Properties for Cascading Variables)的CSS規範終於發佈爲「候選推薦標準」(Candidate Recommendation)。這套規範引入了CSS中「變量」的概念,支持一種新的基於上下文的動態樣式定義方式。你能夠聲明一個變量,再給它賦值,而後就能夠在樣式表的任何地方引用它。你能夠經過這樣的方式,減小樣式表中的重複代碼,以及後續你會看到的一些有用的應用場景。git

在寫這本書的時候,自定義屬性已經被大多數主流瀏覽器支持了,除了IE。查看最新的瀏覽器支持狀況,能夠查看Can I Use的http://caniuse.com/#feat=css-variablesgithub

筆記

若是你恰好在用支持自定義變量的CSS預處理器,如Sass(syntactically awesome stylesheets)或Less,你可能會下意識拒絕CSS變量。千萬別這麼作。由於原生的CSS變量比任何一個預處理器能實現的功能都要強大和靈活。爲了強調它們之間(原生CSS變量和預處理器自定義變量)的差別,我會把它叫做「自定義屬性」,而不用「CSS變量」。瀏覽器

聲明一個自定義屬性,跟聲明其餘屬性相似。代碼片斷2.23是自定義屬性聲明的例子。新建一個頁面和樣式表吧,而後添加如下的CSS代碼。less

 
[ 代碼片斷 2.23 聲明一個自定義屬性 ]ide

:root {
  --main-font: Helvetica, Arial, sans-serif;
}

代碼片斷中,定義了一個名叫--main-font的變量,而後把它的值設定爲普通的字體sans-serif。爲了和其餘屬性區分開,命名的前綴必須是兩道橫槓(--),而後寫上你想要的名字。函數

變量必定要聲明在一個聲明區塊內。在這裏,我使用了:root選擇器,那麼這個變量就能夠在整個頁面的樣式裏使用 —— 後面我會簡單解釋這個問題。

變量的聲明,就它自己而言,不會作任何事情,直到咱們在代碼裏引用它。咱們在一個段落中使用它吧,作成像圖2.13那樣的效果。

 
[ 圖 2.13 對一個簡單段落使用用變量聲明的字體sans-serif ]

"圖 2.13"

咱們能夠用一個叫做var()的函數去引用自定義屬性的值。如今,你能夠利用這個函數去引用咱們剛纔聲明的變量--main-font。把下面展現的代碼片斷添加到你的樣式表中吧,把變量用起來。

 
[ 代碼片斷 2.24 使用一個自定義屬性 ]

:root {
  --main-font: Helvetica, Arial, sans-serif;
}

p {                                    1
  font-family: var(--main-font);       1
}
  • 1 把段落的字體定義爲 Helvetica, Arial, sans-serif

 
自定義屬性可讓你在一個地方聲明它的值,做爲一個「單一數據源」(single source of truth),而後在樣式表的任意一個地方引用。這一點對一些反覆出現的值特別有用,譬如顏色。下一個代碼片斷添加了一個名叫brand-color的自定義屬性。你能夠在樣式表中屢次使用這個變量,但假如你須要(全局)修改它的值,只須要在一行代碼中編輯它的值就能夠了。

 
[ 代碼片斷 2.25 對color使用自定義屬性 ]

:root {
  --main-font: Helvetica, Arial, sans-serif;
  --brand-color: #369;                           1
}

p {
  font-family: var(--main-font);
  color: var(--brand-color);
}
  • 1 聲明一個藍色的brand-color變量

 
var()函數支持第二個參數,表明一個默認值。假如一個變量被聲明的時候,第一個參數沒有被聲明,那麼第二個參數值就會被引用。

[ 代碼片斷 2.26 提供回退默認值 ]

:root {
  --main-font: Helvetica, Arial, sans-serif;
  --brand-color: #369;
}

p {
  font-family: var(--main-font, sans-serif);         1
  color: var(--secondary-color, blue);               2
}
  • 1 聲明一個默認值 sans-serif
  • 2 變量 secondary-color 沒有被聲明,因而默認值 blue 會被使用

 
這段代碼在兩個不一樣的聲明中,定義了默認值。第一個聲明裏,--main-font被聲明,值爲Helvetica, Arial,sans-serif,因而這個值就會被用到了。第二個聲明裏,--secondary-color是一個沒有聲明過的變量,因此默認值 blue 被用到了。

 

筆記
若是 var()被定義爲一個無效值,這個屬性會被定義爲它的初始值。舉個例子,若是在 padding: var(--brand-color)中,變量是一個色號,那對於padding來講這就是一個無效值。在這個狀況下,padding的值會被定義爲0。

 

2.6.1 動態改變自定義屬性的值

從這些例子能夠看到,自定義屬性只是更方便了一點,也能夠幫助你減小不少的重複代碼。但讓自定義屬性更有意思的是,自定義屬性的聲明是能夠層疊和繼承的。你能夠在多個選擇器中聲明同一個變量,這些變量在頁面的不一樣部分能夠有着不同的值。

你能夠聲明一個變量是黑色的,舉個例子,而後在一個特定的容器裏把它從新定義爲白色的。因而,在這個容器之外的全部依賴這個變量的顏色是黑色,而在容器內的就是白色。經過這樣的方式,咱們來實現一個像圖2.14這樣的效果。

 
[ 圖 2.14 自定義屬性基於不一樣域下的值,生成兩個顏色不同的面板 ]

"圖 2.14"

這個面板相似你以前看到的那個(圖2.7),HTML在代碼片斷2.27。這個面板有兩個實例,一個在body下,另外一個在一個深色的區塊。來,更新下你的代碼。

 
[ 代碼片斷 2.27 頁面上不一樣上下文的兩個面板 ]

<body>
  <div class="panel">                               1
    <h2>Single-origin</h2>
    <div class="body">
      We have built partnerships with small farms
      around the world to hand-select beans at the
      peak of season. We then careful roast in
      small batches to maximize their potential.
    </div>
  </div>

  <aside class="dark">                              2
    <div class="panel">                             2
      <h2>Single-origin</h2>
      <div class="body">
        We have built partnerships with small farms
        around the world to hand-select beans at the
        peak of season. We then careful roast in
        small batches to maximize their potential.
      </div>
    </div>
  </aside>
</body>
  • 1 頁面上一個普通的面板
  • 2 第二個面板在深色容器裏

 
咱們用變量從新改寫一下面板中的文字和背景顏色。把下面的代碼片斷加進你的樣式表。這裏把背景顏色設成白色,文字顏色設成黑色。在你添加深色主題以前,我會解釋這段代碼的工做原理。

 
[ 代碼片斷 2.28 利用變量定義面板的顏色 ]

:root {
  --main-bg: #fff;                       1
  --main-color: #000;                    1
}

.panel {
  font-size: 1rem;
  padding: 1em;
  border: 1px solid #999;
  border-radius: 0.5em;
  background-color: var(--main-bg);      2
  color: var(--main-color);              2
}

.panel > h2 {
  margin-top: 0;
  font-size: 0.8em;
  font-weight: bold;
  text-transform: uppercase;
}
  • 1 分別把背景色和文字顏色定義爲白色和黑色
  • 2 在面板樣式中使用變量

 
你再一次把變量聲明在:root選擇器裏。很明顯,這樣的話咱們就能夠在根元素(整個頁面)下的任何元素中引用這個變量了。當根元素下的子元素使用這些變量時,它們就能拿到這些變量對應的值。

你有兩個面板,不過它們仍然看起來是同樣的。如今,再一次定義這些變量,但此次是在一個不一樣的選擇器中。下一個代碼片斷是深色容器的,它有深灰色的背景色,以及小小的padding和margin。同時,它也重寫了兩個變量。添加到你的樣式表吧。

 
[ 代碼片斷 2.29 設置深色容器的樣式 ]

.dark {
  margin-top: 2em;                   1
  padding: 1em;
  background-color: #999;            2
  --main-bg: #333;                   3
  --main-color: #fff;                3
}
  • 1 在深色容器和上一個容器間設定一個margin
  • 2 給深色容器設定深灰色的背景色
  • 3 在當前容器的做用域下,從新定義--main-bg 和 --main-color的值

 
刷新頁面,第二個面板就會有深色背景和白色文字。這是由於當這個面板去調用這些變量時,拿到的是深色容器做用域下的值,而不是根元素域下的值。注意,你並不須要修改這個容器裏的樣式或者添加額外的類名。

在這個例子裏,你兩次定義了自定義屬性,第一次在根元素做用域上(--main-color是黑色的),第二次在深色容器做用域(--main-color是白色的)。自定義屬性表現得像做用域變量,由於值會被後代元素繼承。在深色容器中,--main-color是白色的,而在頁面的其餘位置,它是黑色的。

2.6.2 經過JavaScript改變自定義屬性的值

在瀏覽器中,自定義屬性還能夠被JavaScript訪問和動態地修改。畢竟這不是一本講JavaScript的書,我會告訴你足夠多的基本概念,而後你再把這些融入到本身的JavaScript項目中。

 
[ 代碼片斷 2.30 在JavaScript裏訪問一個自定義變量 ]

<script type="text/javascript">
  var rootElement = document.documentElement;
  var styles = getComputedStyle(rootElement);                 1
  var mainColor = styles.getPropertyValue('--main-bg');       2
  console.log(String(mainColor).trim());                      3
</script>
  • 1 獲取元素的樣式對象(style object)
  • 2 從樣式對象中得到 --main-bg 的值
  • 3 確認 mainColor 是一個字符串以及把空格去掉,輸出「#fff」

 
由於你能夠隨手修改自定義屬性的值,你能夠用JavaScript給--main-bg動態地定義一個新的值。若是你把它定義爲淺藍色,它就是展現成這樣(圖2.15)。

 
[ 圖 2.15 JavaScript能夠經過改變變量--main-bg的值改變面板的背景色 ]

"圖 2.15"

下面的代碼片斷,會在根元素下給--main-bg定義一個新的值,在<script>標籤的最下面,加上這些的代碼。

 
[ 代碼片斷 2.31 在JavaScript定義一個自定義變量的值 ]

var rootElement = document.documentElement;
rootElement.style.setProperty('--main-bg', '#cdf');            1
  • 1 把根元素下的 --main-bg 定義爲淺藍色

 
若是你執行這段代碼,任何繼承了--main-bg屬性的元素都會發生改變,對應的值會變成新的。在你的頁面上,這會把第一個面板的背景色變成淺藍色。第二個面板保持不變,由於它繼承的仍是在深色容器裏定義的值。

利用這項技術,你能夠在瀏覽器裏用JavaScript給你的站點換主題。或者你能夠高亮頁面上的某些部分,又或者隨手就能夠作一些改變。只須要少許幾行JavaScript代碼,你作的改變就能夠影響到頁面上大量的元素。

2.6.3 初探自定義屬性

自定義屬性是一個全新的CSS領域,開發者纔剛剛開始探索。由於目前瀏覽器的支持比較有限,因此尚未到使用它的「黃金時間」。我相信,一段時間以後,你會看到不少關於自定義屬性的最佳實踐和新穎的玩法。這是你須要留意的。嘗試使用自定義屬性,看看你能夠作出些什麼吧。

須要關注的一點,若是你使用var()聲明,低版本瀏覽器不能識別就會忽略它。若是能夠的話,給那些瀏覽器提供一個回退(fallback)方案。

 
[ 代碼片斷(沒有編號) ]

color: black;
color: var(--main-color);

自定義屬性原生的動態特性,並非老是可使用的,能夠關注它的瀏覽器支持狀況http://caniuse.com

總結

  • 擁抱和使用相對單位,讓頁面的結構去定義樣式代碼的含義
  • 我的喜歡對字號大小使用rem,選擇性地對頁面組件的一些簡單縮放效果使用em
  • 你可讓整個頁面實現響應式縮放,而不須要任何的媒體查詢
  • 在聲明行高時,使用不帶單位的數值
  • 開始瞭解和使用CSS最新的特性之一——自定義屬性吧!

《別說你懂CSS相對單位》系列譯文:

  1. 如何更愉快地使用em
  2. 如何更愉快地使用rem
  3. 視口相關單位的應用
  4. 無單位數字和行高
  5. CSS自定義屬性 [本文]

章節:

  • 2.1 相對單位值的魔力

    • 2.1.1 完美像素設計(pixel-perfect design)的掙扎
    • 2.1.2 完美像素網頁的終結
    • 像素(pixel)、點(point)和pc(pica)
  • 2.2 em和rem

    • 2.2.1 對font-size使用em

      • 當咱們在一個元素內用em同時聲明font-size和其餘屬性
      • 字號收縮問題
    • 2.2.2 對font-size使用rem

      • 可用性:對font-size使用相對長度單位
  • 2.3 中止使用像素思惟去思考

    • 2.3.1 設置一個合理的字號默認值
    • 2.3.2 讓這個面板變得「響應式」
    • 2.3.3 調整單個組件的大小
  • 2.4 視口相關單位(viewport-relative units)

    • CSS3
    • 2.4.1 在font-size上使用vw
    • 2.4.2 在font-size上使用calc()
  • 2.5 不帶單位的數字(unitless number)和行高(line-height)
  • 2.6 自定義屬性(也叫「CSS變量」)

    • 2.6.1 動態改變自定義屬性的值
    • 2.6.2 經過JavaScript改變自定義屬性的值
    • 2.6.3 初探自定義屬性
  • 總結
原著版權信息:

做者:Keith J.Grant
書籍:CSS in Depth
章節:Working with relative units


筆者 @Yuying Wu,前端愛好者 / 鼓勵師 / 新西蘭打工度假 / 鏟屎官。目前就任於某大型電商的B2B前端團隊。

感謝你讀到這裏,對上文如有任何疑問或建議,歡迎留言。

若是你和我同樣喜歡前端,喜歡搗騰獨立博客或者前沿技術,或者有什麼職業疑問,歡迎關注我以及各類交流哈。

獨立博客:wuyuying.com
知乎ID:@Yuying Wu
Github:Yuying Wu

相關文章
相關標籤/搜索