標籤:

【譯】CSS變數的正確使用方法

原文:Using CSS variables correctly

原作者:Mike Riethmuller

翻譯:百度外賣FE - 安秦

譯者注

前端的發展真的是好快,這兩年JS的發展幾乎掩蓋了其他前端技術的光芒,然而不知不覺中原生CSS也變得這麼強大。這篇文章不是語法介紹也不是教程,看完之後卻才真正地體會CSS變數的好處。

先簡單說明一下CSS變數目前的規範語法:

  • 用兩個「-」開頭表示聲明變數,如:--white-color: #FFF
  • 用var(...)引用變數值,如:background: var(--white-color)

譯文

CSS變數(又稱自定義屬性)現以得到所有主流瀏覽器的支持,人們已經開始再生產環境中使用它們。這很好,不過它們跟各種預處理器中的變數是不一樣的,而我見過很多例子,寫代碼的人並沒有意識到CSS變數真正的優勢。

它們終究會改變我們CSS的寫法以及思維方法。我認為我有必要做進快速的demo來演示一些CSS變數的正確或者錯誤的使用案例,挺屍也演示它們與預處理器的區別是如何改變我們CSS代碼結構的。

有什麼區別?

首先,它們區別在哪裡?最主要的區別是,CSS變數可以改變。這聽起來一點也不讓人驚訝,變數肯定能變。你可能沒仔細想過,像Sass這樣的預處理器,裡面的變數是靜態的。的確,你可以在編譯過程中的不同時間點改變一個變數的值,但是當它被翻譯成CSS以後他們就是靜態的了。

預處理器里的變數是個非常的好的工具,能夠幫助我們寫出很DRY(dont repeat yourself:不冗餘)並且易於維護的CSS代碼。CSS變數不太一樣,它可以響應頁面上下文變化。

變數作用域可以是靜態或動態的,CSS變數作用域是動態的。

具體來說,動態作用域意味著可以存在繼承與層疊。這很棒,因為這樣你的可以在媒體查詢里或者符合某種選擇器的元素里改變變數的值。同樣的變數可以在頁面的不同位置有不同的值。你甚至可以用JavaScript讀取或更改CSS變數。

如果你沒有仔細想過多少CSS變數的用法,看完這篇文章你就見識到了。不過我會先演示一下CSS變數的錯誤用法。

CSS變數實現縮放模塊化

我將以模塊化(modular scale)為例。縮放模塊化是一種尺寸縮放方法,可用於給標題元素設置合適的尺寸。我很喜歡這麼做,而且還喜歡給不同的屏幕尺寸設置不同的縮放比例。

我想要給小屏幕設置1.2倍縮放,大屏幕1.33倍。我不喜歡算數所以我從modularscale.com獲取以下的數值並用作我的標題元素尺寸:

不要這麼做…

這是個使用CSS變數的完美場景。如果使用Sass的思考方式,也是我如今見過很多人用CSS變數的方式,會是如此:

:root {n /* 1.2倍縮放 */n --ms-small-1: 1em;n --ms-small-2: 1.2em;n --ms-small-3: 1.44rem;n --ms-small-4: 1.728rem;n --ms-small-5: 2.074rem;n --ms-small-6: 2.488rem;n n /* 1.33倍縮放 */n --ms-large-1: 1rem; n --ms-large-2: 1.333rem; n --ms-large-3: 1.777rem;n --ms-large-4: 2.369rem; n --ms-large-5: 3.157rem;n --ms-large-6: 4.209rem;n}n

這看起來很合理,我們為每一種尺寸定義了相應的變數。然後我想就會看到這:

/* 小屏幕有小的縮放比例: */nh1 {n font-size: var(--ms-small-6);n}nh2 {n font-size: var(--ms-small-5);n}nh3 {n font-size: var(--ms-small-4);n}nh4 {n font-size: var(--ms-small-3);n}nh5 {n font-size: var(--ms-small-2);n}nh6 {n font-size: var(--ms-small-1);n}n n/* 大屏幕有大的縮放比例 */n@media screen and (min-width: 800px) {n h1 {n font-size: var(--ms-large-6);n }n h2 {n font-size: var(--ms-large-5);n }n h3 {n font-size: var(--ms-large-4);n }n h4 {n font-size: var(--ms-large-3);n }n h5 {n font-size: var(--ms-large-2);n }n h6 {n font-size: var(--ms-large-1);n }n}n

正常運行!更好的是,如果我希望改變任何一個值我只需要在一處更改。在CSS的其他地方使用變數還會帶來更多的好處。

就像Sass一樣,這很DRY,比普通的CSS要好很多。然而我們可以做得更好。

要像這樣做……

上面的例子看起來邏輯很嚴謹,但是它並沒有真正利用到CSS變數的真正原理。我們再來一次,這次記得CSS變數是根據DOM產生作用域的,所以可以有集成與層疊。

:root {n /* scale for 1.2 */n --font-size-1: 1em;n --font-size-2: 1.2em;n --font-size-3: 1.44rem;n --font-size-4: 1.728rem;n --font-size-5: 2.074rem;n --font-size-6: 2.488rem;n}n n@media screen and (min-width: 800px) {n :root {n /* scale for 1.33 */n --font-size-1: 1rem; n --font-size-2: 1.333rem; n --font-size-3: 1.777rem;n --font-size-4: 2.369rem; n --font-size-5: 3.157rem;n --font-size-6: 4.209rem;n }n}n

注意我這次只有一組變數,而不是每種縮放比例都有一組。我是根據屏幕尺寸改變變數的值。這種寫法導致:

  1. 我必須改變變數的命名方式(不再有small或large)
  2. CSS的其他地方不再需要有媒體查詢

我現在可以在我的屬性定義當中直接使用變數,並且知道它們會根據需要而改變。所有響應式邏輯都在變數里。剩下的CSS就如下即可:

h1 {n font-size: var(--font-size-6);n}nh2 {n font-size: var(--font-size-5);n}nh3 {n font-size: var(--font-size-4);n}nh4 {n font-size: var(--font-size-3);n}nh5 {n font-size: var(--font-size-2);n}nh6 {n font-size: var(--font-size-1);n}n

以上的例子展示了一種更好的方式來使用CSS變數。

CSS變數代碼結構的組織技巧

變數是可以根據CSS結構而變化的,尤其在於響應式設計相關的方面。

邏輯與設計分離:

最大的優勢是,我們現在可以完全分離邏輯與設計。更明確的說法是,我們可以把變數聲明與屬性聲明分開。

.this-is-a-variable-declaration {n --my-var: red;n}nn.this-is-a-property-declaration {n background: var(--my-var)n} n

在用預處理器的時候,把變數與其餘的定義聲明分開是很好的實踐方式,用CSS變數時也應如此。

改變值而不是變數:

在大多數情況中,我認為在媒體查詢或選擇器中用另一個變數覆蓋原有的變數是很臭的寫法。與其改變引用的變數,更好的做法是只定義一個變數,設置一個廚師值然後在媒體查詢或選擇器中改變它的值。

如果它會變那就是個變數:

我相信在多數情況下,響應式設計邏輯應該用變數實現。這裡還有過很激烈的討論,不論是在媒體查詢或是元素作用域中,如果有任何屬性值是需要變化的,它就應該使用變數。如果它會變,那麼它從字面上講就是個變數,那麼這個邏輯就應該與設計分離。

減少媒體查詢:

講道理,所有與變數相關的邏輯都應該放到文檔的最開頭。這樣更好維護,因為你可以在一個地方改變它們,這樣也更好閱讀,因為你不用看整個樣式代碼就可以知道有哪些東西會發生變化。

用媒體查詢達不到這樣的效果,因為它會需要把對同一個元素的樣式定義分成碎片並分布到代碼的不同位置。這樣的做法操作麻煩還不好維護,所以只好把媒體查詢與被他們影響的選擇器放到一起。

用變數就可以將邏輯與設計的實現聯繫起來。這就是說,通常媒體查詢除了修改變數值就不再有別的需求了,然後它們應該存在於文檔的開頭語變數聲明放在一起。以上,「邏輯摺疊」。

簡化選擇器:

將邏輯與設計里可以簡化你的主要屬性聲明以至於你可以把很多選擇器直接組合在一起。

這個例子,我有一個側邊欄和一個主元素,它們擁有不同的字體大小。側邊欄有深色背景而主元素有淺色背景。

/* 變數默認值 */n:root {n --font-size: 1.2em;n --background-color: #fff;n --text-color: #222;n}n/* 側邊欄的變數值 */naside {n --font-size: 1em;n --background-color: #222;n --text-color: #FAFAFA;n}n n/* 相同的屬性聲明 */nmain,naside {n font-size: var(--font-size);n color: var(--text-color);n background-color: var(--background-color);n}n

雖然擁有完全不一樣的樣式,這兩個元素卻擁有一樣的屬性定義。

減少通用變數:

提一個警告:不要使用過於通用的變數。你也許會覺得搞個全局選擇器,然後使用變數實現所有的邏輯很有趣:

/* 別這樣 */n*{n display: var(--display);n width: var(--width);n height: var(--height);n border: var(--border);n background: var(--background);n ...n}n

雖然很好玩,但是我們應當謹慎地復用變數以及合併選擇器。CSS變數會響應層疊定義,按照上面的例子,當給.container如下設置邊框時:

.container {n --border: solid 2px tomato;n}n

所有在這個容器里的元素都會繼承相同的邊框。很快你就需要給所有的元素重設變數,不用 * 全局選擇器就不會栽入這個坑。

利用預處理器使用靜態變數:

CSS變數可以完全替代預處理器?並不能,使用預處理器依然有意義。所有的靜態變數保持使用Sass(或其他什麼你正在用的預處理器)是很好的想法。

// 靜態變數:n$breakpoint-small: 600px;n$theme-color: rebeccapurple;nn// 動態變數n@media screen and (min-width: $breakpoint-small) {n body {n background: $theme-color;n }n}n

這不光是演示在用靜態變數表示一個會動態變化的值,事實上CSS變數只能在屬性聲明中引用,不能在媒體查詢里引用。預處理器還有顏色計算函數、mixin以及文件拆分,這些東西依然有用。

新的響應式設計實現方案

我認為CSS變數提供了一種全新的方式來實現響應式設計,並且會挑戰很多我們已經習慣使用的技巧以及思維方式,以上只是一些顯而易見的的提示。

我圍繞文中介紹的一些技巧與建議做了一個簡單的例子:Responsive design with CSS variables,我極力推薦大家去研究一下這代碼。


推薦閱讀:

CSS 新的長度單位 fr 你知道么?
實現CSS居中的多種方法
詳解 CSS 居中布局技巧
CSS原理解析之模型篇

TAG:CSS |