[CSS] 自定義變量帶你爲所欲爲,一鍵換膚

認識CSS自定義變量

CSS自定義屬性?聽着怎麼那麼神奇呢,屬性還能夠自定義,那不是能夠放肆地玩耍?我本身定義的屬性瀏覽器都能認識?css

1、基礎

(一)名字和用途

其實CSS自定義屬性還有不少小名,好比CSS變量原生變量CSS自定義屬性級聯變量,這些指的都是同個東西。html

說到變量,在SCSS\LESS等CSS預處理器中你們都已經常常運用,說來有幾點好處:ios

一、能使用顏色變量統一風格;
二、能夠採用一致的組件屬性,包括佈局和定位等;
三、避免代碼冗餘。css3

那既然SCSS就能作到的東西,咱們還有這個所謂的CSS自定義變量幹什麼呢?人家天然有它的獨到之處。web

一、好比能夠在運行時改寫,具有動態性;
二、好比方便使用JS讀取和改寫;
三、好比可繼承、可組合、同時具備做用域。小程序

在這幾個方面,預處理器徹底被CSS自定義變量KO了。瀏覽器

(二)聲明變量

語法很簡單,分紅兩步,聲明變量使用變量bash

聲明變量使用的是--前綴。wordpress

:root{
    --*: xxxx;
    /* --variety-name: variety-value; */
}
複製代碼

這裏須要注意幾個點:函數

  1. :root匹配的就是HTML中的<html>元素,具備最高的權重,:root聲明的變量就是全局變量;
  2. CSS自定義變量對大小寫敏感,--color--Color是兩個變量;
  3. 變量必須聲明在{}中,若是在這裏把它理解爲屬性就更好記憶了,畢竟咱們不會把CSS屬性寫到括號外邊去;
  4. *號表明的就是咱們給變量起的名字。起名字這事真的很煩人,還好CSS變量的名稱限制不多,除了一些特殊關鍵字符不能使用,正常來講你用數字/字母/下劃線_/短橫線-都是沒問題的,聽說還可使用中文、日文和韓文。
:root{
    --黑色:#000;
}

body{
    background: var(--黑色);
}
複製代碼

手賤如我試了一下,真的能夠識別。可是,爲了世界和平請答應我不要這麼寫。

(三)使用變量

很簡單,就是咱們很熟悉的var關鍵字。

/* 定義變量 */
:root{
    --*: #000;
    /* 例如 --color-bg: #000; */
}

/* 使用變量 */
body{
    background: var(--*);
    /* 例如 background: var(--color-bg); */
}
複製代碼

還有一種設置默認值的使用,就是在變量名稱後面,加上一個默認值。

.div{
    background: var(--變量名稱,[默認值]);
    /* 例如 background: var(--color-bg, #000); */
}
複製代碼

也就是說,當這個變量沒有被聲明過的話,就會使用默認值,不至於沒着沒落的。

注意這裏的狀況是變量沒有被聲明過,要是變量是聲明過的,可是使用起來是不合法的,那麼就會採用原來屬性的缺省默認值,並非後面這個你設定的默認值。

p{
    background-color: var(--color, #000);
    /* --color沒有聲明過,因此這裏的p元素背景顏色時候用了默認值#000 */
}
複製代碼
div{
    --color: 20px;
    background-color: var(--color, #000);
    /* 很明顯,background-color: 20px;是有語法錯誤的,因此這裏div的背景色爲透明,取的是這個屬性的默認值 */
}
複製代碼

(四)做用域和權重

一、若是你須要定義一個全局的變量,那麼能夠放在:root根元素下面;
二、若是隻須要在部分元素/組件下使用,就定義在相關的類下面;
三、另外還能夠在@media媒體查詢中或者:hover等僞類中使用。

理解了做用域,那麼權重也是一樣的道理,由於CSS自定義變量是能夠繼承的,因此權重跟咱們平時的屬性權重理解是同樣的。

這裏引用一下張鑫旭大神的例子給你們出道題。

:root{
    --color: purple;
}
div{
    --color: green;
}
#alert{
    --color: red;
}
*{
    color: var(--color);
}
複製代碼
<p>請問我是什麼顏色</p>
<div>請問我是什麼顏色</div>
<div id="alert">
    請問我是什麼顏色
    <p>請問我是什麼顏色</p>
    <p style="--color: grey;">請問我是什麼顏色</p>
</div>
複製代碼

答案以下:

(五)變量的其餘組合

除了上述的一些用法,CSS自定義變量也可使用calc()函數進行計算,或者進行字符串拼接。

這裏舉了三個例子,具體的說明在註釋中。

p{
    --fz: 50;
    font-size: var(--fz)px;
    /* 不要太天真,這樣是錯的 */
}
複製代碼
p{
    --fz: 50;
    font-szie: calc(var(--fz) * 1px);
    /* 若是你必定要這麼用,可使用calc計算函數 */
}
複製代碼
p::after{
    --text: "hellp";
    content: var(--text) " word";
    /* 可是字符串的拼接是能夠實現的 */
}
複製代碼

固然,變量不止能夠直接使用,直接或者經過計算把值傳遞給另外一個變量也是可行的。

p{
    --fz: 20px;
    --fz-lg: var(--fz);
    font-size: var(--fz-lg);
    /* 直接傳遞 */
}
複製代碼
p{
    --fz: 20px;
    --fz-lg: calc(var(--fz) * 1.5);
    font-size: var(--fz-lg);
    /* 經過計算後傳遞 */
}
複製代碼

2、在JS中使用

讀:getPropertyValue( )

寫:setProperty( )

好比說,你在:root上定義了一個color變量,用於設置頁面的主題色,那麼經過下面的JS,你就能夠很簡單地改變color變量的值,從而改變頁面的主題色。換個皮膚,so easy。

// 讀取數據
const rootStyles = getComputedStyle(document.documentElement);
const varValue = rootStyles.getPropertyValue('--color').trim();

// 改寫數據
document.documentElement.style.setProperty('--color', value);
複製代碼

固然用處不止用來換膚,充分發揮你的想象力,看看CSS變量與JS的結合能產生什麼樣奇妙的效果~附上大漠老師的小DEMO

應用CSS自定義變量

介紹了這麼多,那麼CSS自定義變量到底都在什麼場景下應用呢?

1、CSS禪意花園

最強的應用固然是一鍵換膚啦!

通常狀況下,咱們如果想根據不一樣的合做方或者不一樣的應用更換主題顏色,通常使用預處理器先定義一個全局主題顏色,如:

$theme-color: #f00;

button{
    background: $theme-color;
}
複製代碼

最後編譯獲得一個定製的CSS文件,如:

button{
    background: #f00;
}
複製代碼

這樣咱們就能夠經過引入這個特殊的CSS文件,獲得一套主題色爲紅色的頁面樣式。

第一種形式適用於,功能通用可是最後根據配置輸出一個產品的獨立管理臺一個獨立小程序等,這樣用本身一套獨有的CSS文件就很方便。

可是若是咱們提供一個通用的產品去接入不一樣的合做方,接入方都有定製主題的需求,就能夠選擇預處理器或CSS自定義屬性。

/* 預處理器方式,先定義不一樣的主題色 */
$theme-color-a: #f00;
$theme-color-b: #0f0;

/* 在頁面層級最外層加上定製的類名,類名中全部樣式都須要從新覆蓋一遍 */
.project-a{
    button{
        background: $theme-color-a;
    }
    a{
        color: $theme-color-a;
    }
}
.project-b{
    button{
        background: $theme-color-b;
    }
    a{
        color: $theme-color-b;
    }
}

/* 或者在媒體查詢中須要重置樣式 */
$fz-sm: 12px;
$fz-md: 14px;

button{
    font-size: $fz-sm;
}
a{
    font-size: $fz-sm;
}

@media (min-width: 375px){
    button{
        font-size: $fz-md;
    }
    a{
        font-size: $fz-md;
    }
}
複製代碼
:root{
    --FZ: 12px;
}
/* 照常寫一套樣式 */
button{
    background: var(--THEME-COLOR, #fff);
}
a{
    color: var(--THEME-COLOR, #fff);
}

/* 根據不一樣的接入方設置主題色 */
.project-a{
    --THEME-COLOR: #f00;
}
.project-b{
    --THEME-COLOR: #0f0;
}

@media (min-width: 375px){
    :root{
        --FZ: 14px;
    }
}
複製代碼

這種需求在CSS預處理器中沒法實現一個沒有複製代碼的方案,老是須要覆蓋實現的值和規則,這也常常會致使CSS冗餘。

使用CSS自定義屬性,解決方案是儘量的簡潔,也避免複製和粘貼代碼,由於只要從新定義變量的值,不須要去覆蓋一次樣式。

第二種方式中兩個方式的區別則是,預處理器中變量的做用域是沒法繼承的,而CSS自定義變量則相對靈活,這樣一旦接入方多了以後,兩種方式的代碼量就會有質的區別。

以上兩種方式都仍是直接把主題色配置在CSS中。可是若是須要接入管理臺,讓合做方直接在管理臺設置主題色的話,預處理器這種靜態的方式就直接退出了競爭,CSS自定義屬性的絕對優點就出來了。

:root{
    --THEME-COLOR: #fff;
}
button{
    background: var(--THEME-COLOR);
}
a{
    color: var(--THEME-COLOR);
}
複製代碼
let value = #f00; //或者經過請求獲取配置的主題色
document.documentElement.style.setProperty('--THEME-COLOR', value);
複製代碼

第三種方式則很是靈活,咱們能夠經過管理臺或者其餘配置的方式,傳遞合做方主題色,一鍵應用便可。

歷史性的時刻誕生了,今後接入就是分分鐘的事,直接讀取管理臺的配置,更改CSS自定義屬性。來個小DEMO體驗一下吧。

codepen.io/Apollozz/pe…

2、主題色處理

預處理器提供了不少高級的顏色方法,能夠實現顏色的高亮、變暗或去飽和等等;

$color: #f00; 

.lighten{
    background: lighten($color,10%);
}
.darken{
    background: darken($color,10%);
}
.desaturate{
    background: desaturate($color,10%);
}
複製代碼

這樣編譯出來的結果就是

.lighten{
    background: #ff3333;
}
.darken{
    background: #cc0000;
}
.desaturate{
    background: #f20d0d;
}
複製代碼

這些方法沒法直接使用在CSS自定義屬性中,可是咱們能夠經過rgb( )或者hsl( )來調整主題顏色的色調或亮度。

(一)使用rgb改變顏色

rgb顏色變亮變暗的原理相對簡單,只需修改--COLOR-R/--COLOR-G/--COLOR-B的值,利用calc函數對rgb的值進行線性增減便可。

:root{
  --COLOR-R: 25;
  --COLOR-G: 153;
  --COLOR-B: 112;
  --DARKEN: 30; // 加深程度
  --LIGHTEN: 30; // 變亮程度
  --THEME-COLOR: rgb(var(--COLOR-R), var(--COLOR-G), var(--COLOR-B));
  --THEME-COLOR-DARKEN: rgb(calc(var(--COLOR-R) - var(--DARKEN)), calc(var(--COLOR-G)  - var(--DARKEN)), calc(var(--COLOR-B) - var(--DARKEN)));
  --THEME-COLOR-LIGHTEN: rgb(calc(var(--COLOR-R) + var(--LIGHTEN)), calc(var(--COLOR-G)  + var(--LIGHTEN)), calc(var(--COLOR-B) + var(--LIGHTEN)));
}
複製代碼

codepen.io/Apollozz/pe…

(二)使用hsl改變顏色

rgb咱們可能相對熟悉,可是hsl用得比較少,下面簡單介紹一下hsl的原理,詳細內容請點擊連接。

與RGB使用的三色光不一樣,HSL一樣使用了3個份量來描述色彩,HSL色彩的表述方式是:H(hue)色相,S(saturation)飽和度,以及L(lightness)亮度。

HSL的H(hue)份量,表明的是人眼所能感知的顏色範圍,這些顏色分佈在一個平面的色相環上,取值範圍是0°到360°的圓心角,每一個角度能夠表明一種顏色。

HSL的S(saturation)份量,指的是色彩的飽和度,它用0%至100%的值描述了相同色相、明度下色彩純度的變化。數值越大,顏色中的灰色越少,顏色越鮮豔,呈現一種從理性(灰度)到感性(純色)的變化。

HSL的L(lightness)份量,指的是色彩的明度,做用是控制色彩的明暗變化。它一樣使用了0%至100%的取值範圍。數值越小,色彩越暗,越接近於黑色;數值越大,色彩越亮,越接近於白色。

通常來講,咱們須要按鈕在hover狀態時加深顏色,此時應用的原理是將顏色的hsl值中的L也就是亮度調低。

:root{
  --COLOR-H: 29;
  --COLOR-S: 100;
  --COLOR-L: 50;
  --DARKEN: 0.15;
  --THEME-COLOR: hsl(var(--COLOR-H), calc(var(--COLOR-S) * 1%), calc(var(--COLOR-L) * 1%));
  --THEME-COLOR-DARKEN: hsl(var(--COLOR-H), calc(var(--COLOR-S) * 1%), calc(var(--COLOR-L) * (1 - var(--DARKEN)) *  1%));
  --THEME-COLOR-LIGHTEN: hsl(var(--COLOR-H), calc(var(--COLOR-S) * 1%), calc(var(--COLOR-L) * (1 + var(--DARKEN)) *  1%));
}
複製代碼

codepen.io/Apollozz/pe…

(三)使用遮罩改變顏色

若是不經過改變色值來改變顏色的話,能夠選擇遮上一個半透明的蒙層來改變顏色,加深顏色則選擇黑色半透明蒙層,提亮顏色則選擇白色半透明蒙層。

.button_color{
    position: relative;
    color: #fff;
    background: var(--THEME-COLOR);
    border: 1px solid var(--THEME-COLOR);
    &:after{
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        transition: all 0.2s;
    }
    /* 黑色半透明蒙層 */
    &:hover:after{
        background: rgba(0,0,0,0.05);
    }
    /* 白色半透明蒙層 */
    &.lighten:hover:after{
        background: rgba(255,255,255,0.1);
    }
}
複製代碼

codepen.io/Apollozz/pe…

3、兼容性

目前CSS自定義變量的兼容性仍是比較可觀的,新的主流瀏覽器都支持。

PC端主要是IE這塊硬石頭,而移動端則主要是低端機型系統例如ios9.2及如下/安卓4.4及如下不支持,這樣的兼容性已經足以容許讓咱們在項目中開始使用CSS自定義屬性,並對一些低端版本進行下降兼容處理。

對於不支持的瀏覽器能夠採用下列兼容方式:

方案1:直接設置一個默認顏色

直接使用普通的屬性定義,兼容全部的瀏覽器,保證顯示正常。

button{
    background: #F00;
    /* 默認顏色,若不支持CSS自定義屬性則應用該默認顏色 */
    background: var(--THEME-COLOR, #F00);
    /* 在實踐中發現有些機型雖然能識別到CSS自定義變量可是沒法獲取正確顏色,只能獲取到默認值 */
}
複製代碼

方案2:CSS根據@supports判斷是否兼容並適配

低端機型也沒法正確識別@supports,@supports的兼容性只比CSS自定義變量好一丟丟。

@supports ( (--a: 0)) {
  /* supported */
}

@supports ( not (--a: 0)) {
  /* not supported */
}
複製代碼

方案3:js根據@supports判斷是否兼容並適配

const isSupported =
  window.CSS &&
  window.CSS.supports &&
  window.CSS.supports('--a', 0);

if (isSupported) {
  /* supported 引入支持自定義變量的CSS,容許更改CSS自定義變量 */
} else {
  /* not supported 引入兼容的CSS文件 */
}
複製代碼

4、注意事項

  1. 在一些瀏覽器中,針對CSS變量的複雜calc()運算可能不能工做;
  2. 進行calc()運算時,最好能提供默認值:calc(var(--base-line-height, 0) * 1rem)
  3. 不能做爲媒體查詢值使用:
@media screen and (min-width: var(--desktop-breakpoint) ) { 
};
複製代碼
  1. 圖片地址,如url( var(--image-url) ) ,不會生效;
  2. 由於CSS自定義變量對大小寫敏感,故建議全局變量使用全大寫形式,除了設置總體主題色,儘可能減小改動全局變量;
  3. web端可將主題顏色等變量設置在根元素html,並經過上述方法修改自定義屬性的值;
  4. 小程序因沒法獲取DOM,沒法直接修改CSS自定義屬性的值,能夠採起在頁面的最外層元素設置行內樣式的方式重置自定義屬性的值,如:
.container{
    --THEME-COLOR: #f00;
}
複製代碼
<view class="container" style="--THEME-COLOR: #0f0;"> 
    <!-- 該結構下的元素,重置爲行內樣式的主題色 -->
</view>
複製代碼

5、小結

  1. CSS自定義變量目前已支持各主流瀏覽器,低端版本能夠採用兼容方案;
  2. SCSS變量和CSS自定義變量有本質上的區別,用來解決不一樣場景下的問題,CSS自定義屬性用於動態主題,預處理器變量用於靜態模板,項目中能夠根據狀況結合運用效果更佳;
  3. 在媒體查詢中使用自定義變量的話,這樣響應式設計相關的邏輯與正常的設計雖然分離,可是不管咱們在哪裏看到var( )聲明語句,咱們都能很明顯的知道這個屬性會發生變化。而使用傳統的CSS方式,咱們是沒法察覺這一點的,這樣代碼的可讀性就高了不少。

參考資料

  1. 【譯】CSS自定義屬性的策略指南
  2. 深刻學習CSS自定義屬性
  3. 小tips:瞭解CSS/CSS3原生變量var
相關文章
相關標籤/搜索