CSS自定義屬性 —— 別說你懂CSS相對單位
來自專欄集異璧6 人贊了文章
前段時間試譯了Keith J.Grant的CSS好書《CSS in Depth》,其中的第二章《Working with relative units》,書中對relative units的講解和舉例可以說相當全面,看完之後發現自己並不太懂CSS相對單位,也希望分享給大家,所以有了這個譯文系列。(若有勘誤或翻譯建議,歡迎 Github PR ^_^
)
《別說你懂CSS相對單位》系列譯文:
- 如何更愉快地使用em
- 如何更愉快地使用rem
- 視口相關單位的應用
- 無單位數字和行高
- CSS自定義屬性 [本文]
本文對應的章節目錄:
- 2.6 自定義屬性(也叫「CSS變數」)
- 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中「變數」的概念,支持一種新的基於上下文的動態樣式定義方式。你可以聲明一個變數,再給它賦值,然後就可以在樣式表的任何地方引用它。你可以通過這樣的方式,減少樣式表中的重複代碼,以及後續你會看到的一些有用的應用場景。
在寫這本書的時候,自定義屬性已經被大多數主流瀏覽器支持了,除了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 ]
我們可以用一個叫作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.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的值改變面板的背景色 ]
下面的代碼片段,會在根元素下給--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相對單位》系列譯文:
- 如何更愉快地使用em
- 如何更愉快地使用rem
- 視口相關單位的應用
- 無單位數字和行高
- 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 WuGithub:Yuying Wu推薦閱讀:
※大前端應用開發與架構設計-使用CSS美化Web站點(一)
※在創建table表格時,當心「神秘人」改了你的代碼,而你卻不知道!
※css選擇器規則
※前端秘籍,CSS垂直居中必學八式,一招一式盡顯功力
※為什麼17年來Firefox一直不支持CSS定義滾動條樣式呢?