玩轉(zhuǎn) CSS 變量

基礎(chǔ)用法
/* 在 body 選擇器中聲明了兩個變量 */body {--primary-color: red;/* 變量名大小寫敏感,--primary-color 和 --PRIMARY-COLOR 是兩個不同變量 */--PRIMARY-COLOR: initial;}/** 同一個 css 變量,可以在多個選擇器內(nèi)聲明。優(yōu)先級高的會替換優(yōu)先級低的 */main {--primary-color: blue;}/** 使用 css 變量 */.text-primary {/* var() 函數(shù)用于讀取變量。*/color: var(--primary-color)}redblue purple這里我們可以看到針對同一個 css 變量,可以在多個選擇器內(nèi)聲明。讀取的時候,優(yōu)先級最高的聲明生效。 這與 css 的"層疊"(cascade)規(guī)則是一致的。 由于這個原因,全局的變量通常放在根元素:root里面,確保任何選擇器都可以讀取它們。 :root {--primary-color: #06c;}同時, css 變量提供了 JavaScript 與 css 通信的方法。就是利用 js 操作 css 變量。我們可以使用: /* ...和上面 CSS 一致 */redblue // 利用正則去替換 Less 變量 為 CSS 變量.theme(@property, @imp) {@{property}: e(replace(@imp, '@([^() ]+)', '@{$1}', 'ig'));@{property}: e(replace(@imp, '@([^() ]+)', 'var(--$1, @{$1})', 'ig'));}函數(shù)效果如下所示: @import '../common/style/theme.less';.van-button {// ... 其他省略.theme(height, '@button-default-height');.theme(line-height, '@button-line-height');.theme(font-size, '@button-default-font-size');}// => less 編譯之后生成.van-button{// ... 其他省略height:44px;height:var(--button-default-height,44px);line-height:20px;line-height:var(--button-line-height,20px);font-size:16px;font-size:var(--button-default-font-size,16px);}我們可以看到每調(diào)用一次 Less 函數(shù)將會被編譯成兩個屬性。第一個屬性的設(shè)定對于不支持 CSS 變量的設(shè)備可以直接使用,如果當(dāng)前設(shè)備支持 CSS 變量,則會使用 CSS 變量,但是由于當(dāng)前 CSS 變量未定義,就會使用變量的默認(rèn)值。 雖然 '@button-default-height 雖然也是一個變量,但是該變量僅僅只是 less 變量,最終生成的代碼中并沒有 --button-default-height 這樣的變量。 此時我們就可以在使用樣式的位置或者 :root 中添加變量 --button-default-height。 這種方式更適合組件開發(fā),因為該方案不聲明任何 css 變量,只是預(yù)留的 css 變量名稱和默認(rèn)屬性。 這樣的話,無論開發(fā)者的選擇器優(yōu)先度有多低,代碼都可以很容易的覆蓋默認(rèn)屬性。因為我們僅僅使用 css 的默認(rèn)值。 大家可能有時候會想,這樣的話,我們不是有更多的代碼了嗎?其實未必,事實上我們可以直接直接在頁面內(nèi)部定義變量樣式。 其他組件直接通過 style 去使用頁面內(nèi)的變量。當(dāng)然了,事實上書寫的代碼多少,重點在于想要控制默認(rèn)樣式的粒度大小。 粒度越小,則需要在各個組件內(nèi)部書寫的變量越多,粒度大,我們也就不必考慮太多。 Space Toggle 邏輯切換
CSS 沒有邏輯切換似乎是一種共識,但是我們可以利用選框(單選與多選)和 CSS 變量來實現(xiàn)判斷邏輯。我們先來看看如何使用 CSS 變量。 <style>.red-box {--toggler: ;--red-if-toggler: var(--toggler) red;background: var(--red-if-toggler, green); /* will be red! */}.green-box {--toggler: initial;--red-if-toggler: var(--toggler) red;background: var(--red-if-toggler, green); /* will be green! */}style><divstyle="height: 100px; width: 100px"class="red-box">div><divstyle="height: 100px; width: 100px"class="green-box">div>這里因為一個變量 --toggler 使用空格 或者 initial 而產(chǎn)生了不同的結(jié)果,基于這樣的結(jié)果我們不難想象我們可以觸發(fā)變量的修改而產(chǎn)生不同的結(jié)果。 他不是一個 bug,也不是一個 hack。他的原理完完全全的在 CSS Custom Properties 規(guī)范?中。 This value serializes as the empty string, but actually writing an empty value into a custom property, like --foo: ;, is a valid (empty) value, not the guaranteed-invalid value. If, for whatever reason, one wants to manually reset a variable to the guaranteed-invalid value, using the keyword initial will do this. 解釋如下,事實上 -foo: ; 這個變量并不是一個無效值,它是一個空值。initial 才是 CSS 變量的無效值。其實這也可以理解,css 沒有所謂的空字符串,空白也不代表著無效,只能使用特定值來表示該變量無效。這個時候,我們再回頭來看原來的 CSS 代碼。 .red-box {/* 當(dāng)前為空值 */--toggler: ;/* 因為 var(--toggler) 得到了空,所以得到結(jié)果 為 --red-if-toggler: red */--red-if-toggler: var(--toggler) red;/** 變量是 red, 不會使用 green */background: var(--red-if-toggler, green); /* will be red! */}.green-box {/** 當(dāng)前為無效值 */--toggler: initial;/** 仍舊無效數(shù)據(jù),因為 var 只會在參數(shù)不是 initial 時候進(jìn)行替換 */--red-if-toggler: var(--toggler) red;/** 最終無效值沒用,得到綠色 */background: var(--red-if-toggler, green); /* will be green! *//* 根據(jù)當(dāng)前的功能,我們甚至可以做到 and 和 or 的邏輯* --tog1 --tog2 --tog3 同時為 空值時是 紅色*/--red-if-togglersalltrue: var(--tog1) var(--tog2) var(--tog3) red;/** --tog1 --tog2 --tog3 任意為 空值時是 紅色*/--red-if-anytogglertrue: var(--tog1, var(--tog2, var(--tog3))) red;}新式媒體查詢
當(dāng)我們需要開發(fā)響應(yīng)式網(wǎng)站的時候,我們必須要使用媒體查詢?@media。先看一下用傳統(tǒng)的方式編寫這個基本的響應(yīng)式 CSS: .breakpoints-demo > * {width: 100%;background: red;}@media (min-width: 37.5em) and (max-width: 56.249em) {.breakpoints-demo > * {width: 49%;}}@media (min-width: 56.25em) and (max-width: 74.99em) {.breakpoints-demo > * {width: 32%;}}@media (min-width: 56.25em) {.breakpoints-demo > * {background: green;}}@media (min-width: 75em) {.breakpoints-demo > * {width: 24%;}}同樣,我們可以利用 css 變量來優(yōu)化代碼結(jié)構(gòu),我們可以寫出這樣的代碼: /** 移動優(yōu)先的樣式規(guī)則 */.breakpoints-demo > * {/** 小于 37.5em, 寬度 100% */--xs-width: var(--media-xs) 100%;/** 小于 56.249em, 寬度 49% */--sm-width: var(--media-sm) 49%;--md-width: var(--media-md) 32%;--lg-width: var(--media-gte-lg) 24%;width: var(--xs-width, var(--sm-width, var(--md-width, var(--lg-width))));--sm-and-down-bg: var(--media-lte-sm) red;--md-and-up-bg: var(--media-gte-md) green;background: var(--sm-and-down-bg, var(--md-and-up-bg));}可以看出,第二種 CSS 代碼非常清晰,數(shù)據(jù)和邏輯保持在一個 CSS 規(guī)則中,而不是被?@media 切割到多個區(qū)塊中。這樣,不但更容易編寫,也更加容易開發(fā)者讀。 詳情可以參考 css-media-vars。該代碼庫僅僅只有 3kb 大小,但是卻是把整個編寫代碼的風(fēng)格修改的完全不同。 原理如下所示: /*** css-media-vars* BSD 2-Clause License* Copyright (c) James0x57, PropJockey, 2020*/html {--media-print: initial;--media-screen: initial;--media-speech: initial;--media-xs: initial;--media-sm: initial;--media-md: initial;--media-lg: initial;--media-xl: initial;/* ... */--media-pointer-fine: initial;--media-pointer-none: initial;}/* 把當(dāng)前變量變?yōu)榭罩?*/@media print {html { --media-print: ; }}@media screen {html { --media-screen: ; }}@media speech {html { --media-speech: ; }}/* 把當(dāng)前變量變?yōu)榭罩?*/@media (max-width: 37.499em) {html {--media-xs: ;--media-lte-sm: ;--media-lte-md: ;--media-lte-lg: ;}}其他
繼 CSS 鍵盤記錄器?暴露了 CSS 安全性問題之后,CSS 變量又一次讓我看到了玩技術(shù)是怎么樣的。CSS Space Toggle 技術(shù)不但可以應(yīng)用于上面的功能,甚至還可以編寫 UI 庫 augmented-ui 以及?掃雷?游戲。 這簡直讓我眼界大開。在我有限的開發(fā)生涯中,很難找到類似于 css 這種設(shè)計意圖和使用方式差異如此之大的技術(shù)。 CSS 是很有趣的,而 CSS 的有趣之處就在于最終呈現(xiàn)出來的技能強(qiáng)弱與你自身的思維方式,創(chuàng)造力是密切相關(guān)的。上文只是介紹了 CSS 變量的一些玩法,也許有更多有意思的玩法,不過這就需要大家的創(chuàng)造力了。
評論
圖片
表情

