天天看點

【CSS】8-CSS自定義屬性和變量

前言

一個《别說你懂CSS相對機關》系列文最後一篇了。今日早讀文章由阿裡@Yuying Wu翻譯分享。

@Yuying Wu,前端愛好者&鼓勵師 / 紐西蘭working holiday / 鏟屎官 / 咖啡愛好者。

正文從這開始~~

自定義屬性(也叫“CSS變量”)

在2015年,一個大家期待已久的名為“用作層疊式變量的自定義屬性”(Custom Properties for Cascading Variables)的CSS規範終于釋出為“候選推薦标準”(Candidate Recommendation)。這套規範引入了CSS中“變量”的概念,支援一種新的基于上下文的動态樣式定義方式。你可以聲明一個變量,再給它指派,然後就可以在樣式表的任何地方引用它。你可以通過這樣的方式,減少樣式表中的重複代碼,以及後續你會看到的一些有用的應用場景。

在寫這本書的時候,自定義屬性已經被大多數主流浏覽器支援了,除了IE。檢視最新的浏覽器支援情況,可以檢視Can I Use的http://caniuse.com/#feat=css-variables。

筆記

如果你剛好在用支援自定義變量的CSS預處理器,如Sass(syntactically awesome stylesheets)或Less,你可能會下意識拒絕CSS變量。千萬别這麼做。因為原生的CSS變量比任何一個預處理器能實作的功能都要強大和靈活。為了強調它們之間(原生CSS變量和預處理器自定義變量)的差異,我會把它叫作“自定義屬性”,而不用“CSS變量”。

聲明一個自定義屬性,跟聲明其他屬性類似。代碼片段2.23是自定義屬性聲明的例子。建立一個頁面和樣式表吧,然後添加以下的CSS代碼。

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

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

代碼片段中,定義了一個名叫—main-font的變量,然後把它的值設定為普通的字型sans-serif。為了和其他屬性區分開,命名的字首必須是兩道橫杠(—),然後寫上你想要的名字。

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

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

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

【CSS】8-CSS自定義屬性和變量

我們可以用一個叫作var()的函數去引用自定義屬性的值。現在,你可以利用這個函數去引用我們剛才聲明的變量—main-font。把下面展示的代碼片段添加到你的樣式表中吧,把變量用起來。

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

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

自定義屬性可以讓你在一個地方聲明它的值,作為一個“單一資料源”(single source of truth),然後在樣式表的任意一個地方引用。這一點對一些反複出現的值特别有用,譬如顔色。下一個代碼片段添加了一個名叫brand-color的自定義屬性。你可以在樣式表中多次使用這個變量,但假如你需要(全局)修改它的值,隻需要在一行代碼中編輯它的值就可以了。

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

:root
--main-font: Helvetica, Arial, sans-serif;
--brand-color: #369;
}
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);
color: var(--secondary-color, blue);
}      
  • 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.14這樣的效果。

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

【CSS】8-CSS自定義屬性和變量

這個面闆類似你之前看到的那個(圖2.7),HTML在代碼片段2.27。這個面闆有兩個執行個體,一個在body下,另一個在一個深色的區塊。來,更新下你的代碼。

[ 代碼片段 2.27 頁面上不同上下文的兩個面闆 ]

<body>
<div class="panel">
<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">
<div class="panel">
<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;
--main-color: #000;
}
.panel
font-size: 1rem;
padding: 1em;
border: 1px solid #999;
border-radius: 0.5em;
background-color: var(--main-bg);
color: var(--main-color); 
}
.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;
padding: 1em;
background-color: #999;
--main-bg: #333;
--main-color: #fff;
}      
  • 1 在深色容器和上一個容器間設定一個margin
  • 2 給深色容器設定深灰色的背景色
  • 3 在目前容器的作用域下,重新定義–main-bg 和 –main-color的值

重新整理頁面,第二個面闆就會有深色背景和白色文字。這是因為當這個面闆去調用這些變量時,拿到的是深色容器作用域下的值,而不是根元素域下的值。注意,你并不需要修改這個容器裡的樣式或者添加額外的類名。

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

通過JavaScript改變自定義屬性的值

在浏覽器中,自定義屬性還可以被JavaScript通路和動态地修改。畢竟這不是一本講JavaScript的書,我會告訴你足夠多的基本概念,然後你再把這些融入到自己的JavaScript項目中。

[ 代碼片段 2.30 在JavaScript裡通路一個自定義變量 ]

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

因為你可以随手修改自定義屬性的值,你可以用JavaScript給—main-bg動态地定義一個新的值。如果你把它定義為淺藍色,它就是展示成這樣(圖2.15)。

[ 圖 2.15 JavaScript可以通過改變變量–main-bg的值改變面闆的背景色 ]

【CSS】8-CSS自定義屬性和變量

下面的代碼片段,會在根元素下給—main-bg定義一個新的值,在​

​<script>​

​标簽的最下面,加上這些的代碼。

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

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

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

利用這項技術,你可以在浏覽器裡用JavaScript給你的站點換主題。或者你可以高亮頁面上的某些部分,又或者随手就可以做一些改變。隻需要少量幾行JavaScript代碼,你做的改變就可以影響到頁面上大量的元素。

初探自定義屬性

自定義屬性是一個全新的CSS領域,開發者才剛剛開始探索。因為目前浏覽器的支援比較有限,是以還沒有到使用它的“黃金時間”。我相信,一段時間之後,你會看到很多關于自定義屬性的最佳實踐和新穎的玩法。這是你需要留意的。嘗試使用自定義屬性,看看你可以做出些什麼吧。

需要關注的一點,如果你使用​

​var()​

​聲明,低版本浏覽器不能識别就會忽略它。如果可以的話,給那些浏覽器提供一個回退(fallback)方案。

[ 代碼片段(沒有編号) ]

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

自定義屬性原生的動态特性,并不是總是可以使用的,可以關注它的浏覽器支援情況。

總結

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