<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【CSS】893- 玩轉 CSS 變量

          共 13481字,需瀏覽 27分鐘

           ·

          2021-03-11 18:54


          作者:wsafight

          https://github.com/wsafight/personBlog/issues/25


          如果當年的 CSS  預處理器變量對于初入前端的我來說是開啟了新世界的大門,那么 CSS 變量對于我來說無疑就是晴天霹靂。其功能不但可以優(yōu)雅的處理之前 js 不好處理或不適合的業(yè)務需求。更在創(chuàng)造力無窮的前端開發(fā)者手中大放異彩。

          基礎用法

          在前端的領域中,標準的實現總是比社區(qū)的約定要慢的多,前端框架最喜歡的 $ 被 Sass 變量用掉了。而最常用的 @ 也被 Less 用掉了。官方為了讓 CSS 變量也能夠在 Sass 及 Less 中使用,無奈只能妥協的使用 --。

          <style>
            /* 在 body 選擇器中聲明了兩個變量  */ 
            body {
              --primary-color: red;
              /* 變量名大小寫敏感,--primary-color 和 --PRIMARY-COLOR 是兩個不同變量 */  
              --PRIMARY-COLOR: initial;  
            }

            /** 同一個 CSS 變量,可以在多個選擇器內聲明。優(yōu)先級高的會替換優(yōu)先級低的 */
            main {
              --primary-color: blue;
            }
              
            /** 使用 CSS 變量 */
            .text-primary {
              /* var() 函數用于讀取變量。 */  
              color: var(--primary-color)
            }
          <style>
              
          <!-- 呈現紅色字體,body 選擇器的顏色  -->    
          <div class="text-primary">red</div> 
              
          <!-- 呈現藍色字體,main 選擇器定義的顏色  -->    
          <main class="text-primary">blue</main>
              
          <!-- 呈現紫色字體,當前內聯樣式表的定義  --> 
          <div style='--primary-color: purple" class="text-primary">purple</main>    

          這里我們可以看到針對同一個 CSS 變量,可以在多個選擇器內聲明。讀取的時候,優(yōu)先級最高的聲明生效。這與 CSS 的"層疊"(cascade)規(guī)則是一致的。

          由于這個原因,全局的變量通常放在根元素:root里面,確保任何選擇器都可以讀取它們。

          :root {
            --primary-color#06c;
          }

          同時, CSS 變量提供了 JavaScript 與 CSS 通信的方法。就是利用 js 操作 css 變量。我們可以使用:

          <style>
            /* ...和上面 CSS 一致 */  
          </style>    

          <!-- 呈現黃色字體  -->    
          <div class="text-primary">red</div> 
              
          <!-- 呈現藍色字體,main 選擇器定義的顏色  -->    
          <main id='primary' class="text-primary">blue</main>
              
          <!-- 呈現紫色字體,當前內聯樣式表的定義  --> 
          <div id="secondary" style='--primary-color: purple" class="text-primary">purple</main>    

          <script>
          // 設置變量
          document.body.style.setProperty('
          --primary-color', 'yellow');
                                                                     
          // 設置變量,js DOM 元素 ID 就是全局變量,所以直接設置 main 即可
          // 變?yōu)?nbsp;紅色
          primary.style.setProperty('--primary-color', 'red');    

          // 變?yōu)?nbsp;黃色,因為當前樣式被移除了,使用 body 上面樣式
          secondary.style.removeProperty('--primary-color');

          // 通過動態(tài)計算獲取變量值
          getComputedStyle(document.body).getPropertyValue('--primary-color')

          </script>


          我們可以在業(yè)務項目中定義以及替換 CSS 變量,大家可以參考 mvp.css[1]。該庫大量使用了 CSS 變量并且讓你去根據自己需求修改它。

          :root {
            --border-radius5px;
            --box-shadow2px 2px 10px;
            --color#118bee;
            --color-accent#118bee0b;
            --color-bg#fff;
            --color-bg-secondary#e9e9e9;
            --color-secondary#920de9;
            --color-secondary-accent#920de90b;
            --color-shadow#f4f4f4;
            --color-text#000;
            --color-text-secondary#999;
            --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
            --hover-brightness1.2;
            --justify-important: center;
            --justify-normal: left;
            --line-height150%;
            --width-card285px;
            --width-card-medium460px;
            --width-card-wide800px;
            --width-content1080px;
          }

          我們可以看到基于 CSS 變量,可以更友好的和設計師的設計意圖結合在一起。也易于修改,在業(yè)務項目中合理使用無疑可以事半功倍。

          實現默認配置

          如果讓我來思考,我肯定無法想象出結合 CSS 預處理器 + CSS 變量便可以實現組件樣式的默認配置。這里我先介紹兩個關于該功能的前置知識點:

          事實上,CSS 變量的 var() 函數還可以使用第二個參數,表示變量的默認值。如果該變量此前沒有定義或者是無效值,就會使用這個默認值。

          /* 沒有設置過 --primary-color,顏色默認使用 #7F583F */
          colorvar(--primary-color#7F583F);

          雖然目前 CSS 變量不是新的屬性,但終究不是所有的瀏覽器都支持 CSS 變量的,這里我們還是要考慮一下優(yōu)雅降級。

          /* 對于不支持 CSS 變量的瀏覽器,可以采用下面的寫法。*/
          a {
           /* 顏色默認值 */
            color#7F583F;
            /* 不支持則不識別該條規(guī)則 */  
            colorvar(--primary);
          }

          結合 CSS 處理器 + CSS 變量便可以實現組件樣式的默認配置。這里參考了有贊的 Vant Weapp[2] 的做法。有贊代碼 **theme.less**[3] 如下所示:

          // 先導入所有 Less 變量
          @import (reference) './var.less';

          // 利用正則去替換 Less 變量 為 CSS 變量
          .theme(@property, @imp) {
          @{property}: e(replace(@imp, '@([^() ]+)', '@{$1}', 'ig'));
          @{property}: e(replace(@imp, '@([^() ]+)', 'var(--$1, @{$1})', 'ig'));
          }

          函數效果如下所示:

          @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);
          }

          我們可以看到每調用一次 Less 函數將會被編譯成兩個屬性。第一個屬性的設定對于不支持 CSS 變量的設備可以直接使用,如果當前設備支持 CSS 變量,則會使用 CSS 變量,但是由于當前 CSS 變量未定義,就會使用變量的默認值。雖然 '@button-default-height 雖然也是一個變量,但是該變量僅僅只是 less 變量,最終生成的代碼中并沒有 --button-default-height 這樣的變量。此時我們就可以在使用樣式的位置或者 :root 中添加變量 --button-default-height。

          這種方式更適合組件開發(fā),因為該方案不聲明任何 css 變量,只是預留的 css 變量名稱和默認屬性。這樣的話,無論開發(fā)者的選擇器優(yōu)先度有多低,代碼都可以很容易的覆蓋默認屬性。因為我們僅僅使用 css 的默認值。

          大家可能有時候會想,這樣的話,我們不是有更多的代碼了嗎?其實未必,事實上我們可以直接直接在頁面內部定義變量樣式。其他組件直接通過 style 去使用頁面內的變量。當然了,事實上書寫的代碼多少,重點在于想要控制默認樣式的粒度大小。粒度越小,則需要在各個組件內部書寫的變量越多,粒度大,我們也就不必考慮太多。

          Space Toggle 邏輯切換

          CSS 沒有邏輯切換似乎是一種共識,但是我們可以利用選框(單選與多選)和 CSS 變量來實現判斷邏輯。我們先來看看如何使用 CSS 變量。

          <style>
            .red-box {
              --toggler: ;
              --red-if-togglervar(--toggler) red;
              backgroundvar(--red-if-toggler, green); /* will be red! */
            }
            .green-box {
              --toggler: initial;
              --red-if-togglervar(--toggler) red;
              backgroundvar(--red-if-toggler, green); /* will be green! */
            }

          </style>
          <!-- 寬度高度為 100px 的 紅色盒子 -->
          <div 
            style="height: 100px; width: 100px" 
            class="red-box"
          ></div>
           
          <!-- 寬度高度為 100px 的 綠色盒子 -->
          <div 
            style="height: 100px; width: 100px" 
            class="green-box"
          ></div>
           

          這里因為一個變量 --toggler 使用空格 或者 initial 而產生了不同的結果,基于這樣的結果我們不難想象我們可以觸發(fā)變量的修改而產生不同的結果。

          他不是一個 bug,也不是一個 hack。他的原理完完全全的在 CSS Custom Properties 規(guī)范[4] 中。

          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 {
            /* 當前為空值 */
            --toggler: ;

            /* 因為 var(--toggler) 得到了空,所以得到結果 為 --red-if-toggler:  red */
            --red-if-togglervar(--toggler) red;
            /** 變量是 red, 不會使用 green */
            backgroundvar(--red-if-toggler, green); /* will be red! */
          }
          .green-box {
            /** 當前為無效值 */
            --toggler: initial;
            /** 仍舊無效數據,因為 var 只會在參數不是 initial 時候進行替換 */
            --red-if-togglervar(--toggler) red;
            /** 最終無效值沒用,得到綠色 */
            backgroundvar(--red-if-toggler, green); /* will be green! */

            /* 根據當前的功能,我們甚至可以做到 and 和 or 的邏輯 
             * --tog1 --tog2 --tog3 同時為 空值時是 紅色
             */

            --red-if-togglersalltruevar(--tog1) var(--tog2) var(--tog3) red;

           /*
            * --tog1 --tog2 --tog3 任意為 空值時是 紅色
            */
           
            --red-if-anytogglertruevar(--tog1, var(--tog2, var(--tog3))) red;
          }

          新式媒體查詢

          當我們需要開發(fā)響應式網站的時候,我們必須要使用媒體查詢 @media。先看一下用傳統(tǒng)的方式編寫這個基本的響應式 CSS:

          .breakpoints-demo > * {
            width100%;
            background: red;
          }

          @media (min-width: 37.5emand (max-width: 56.249em) {
            .breakpoints-demo > * {
              width49%;
            }
          }

          @media (min-width: 56.25emand (max-width: 74.99em) {
            .breakpoints-demo > * {
              width32%;
            }
          }

          @media (min-width: 56.25em) {
            .breakpoints-demo > * {
              background: green;
            }
          }

          @media (min-width: 75em) {
            .breakpoints-demo > * {
              width24%;
            }
          }

          同樣,我們可以利用 css 變量來優(yōu)化代碼結構,我們可以寫出這樣的代碼:

          /** 移動優(yōu)先的樣式規(guī)則 */
          .breakpoints-demo > * {
            /** 小于 37.5em, 寬度 100%  */
            --xs-widthvar(--media-xs) 100%;

            /** 小于 56.249em, 寬度 49%  */
            --sm-widthvar(--media-sm) 49%;

            --md-widthvar(--media-md) 32%;
            --lg-widthvar(--media-gte-lg) 24%;
            

            widthvar(--xs-width, var(--sm-width, var(--md-width, var(--lg-width))));

            --sm-and-down-bgvar(--media-lte-sm) red;
            --md-and-up-bgvar(--media-gte-md) green;
            backgroundvar(--sm-and-down-bg, var(--md-and-up-bg));
          }

          可以看出,第二種 CSS 代碼非常清晰,數據和邏輯保持在一個 CSS 規(guī)則中,而不是被 @media 切割到多個區(qū)塊中。這樣,不但更容易編寫,也更加容易開發(fā)者讀。詳情可以參考 css-media-vars[5]。該代碼庫僅僅只有 3kb 大小,但是卻是把整個編寫代碼的風格修改的完全不同。原理如下所示:

            
          /**
           * 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;
          }

          /* 把當前變量變?yōu)榭罩?nbsp;*/
          @media print {
            html { --media-print: ; }
          }

          @media screen {
            html { --media-screen: ; }
          }

          @media speech {
            html { --media-speech: ; }
          }

          /* 把當前變量變?yōu)榭罩?nbsp;*/
          @media (max-width: 37.499em) {
            html {
              --media-xs: ;
              --media-lte-sm: ;
              --media-lte-md: ;
              --media-lte-lg: ;
            }
          }

          其他

          CSS 鍵盤記錄器[6] 暴露了 CSS 安全性問題之后,CSS 變量又一次讓我看到了玩技術是怎么樣的。CSS Space Toggle 技術不但可以應用于上面的功能,甚至還可以編寫 UI 庫 augmented-ui[7] 以及  掃雷[8] 游戲。這簡直讓我眼界大開。在我有限的開發(fā)生涯中,很難找到類似于 css 這種設計意圖和使用方式差異如此之大的技術。

          CSS 是很有趣的,而 CSS 的有趣之處就在于最終呈現出來的技能強弱與你自身的思維方式,創(chuàng)造力是密切相關的。上文只是介紹了 CSS 變量的一些玩法,也許有更多有意思的玩法,不過這就需要大家的創(chuàng)造力了。

          augmented-ui[9]

          css-media-vars[10]

          css-sweeper[11]

          參考資料

          [1]mvp.css: https://andybrewer.github.io/mvp/

          [2]Vant Weapp: https://youzan.github.io/vant-weapp/#/theme

          [3]theme.less:https://github.com/youzan/vant-weapp/blob/v1.1.0/packages/common/style/theme.less

          [4]CSS Custom Properties 規(guī)范: https://drafts.csswg.org/css-variables/#guaranteed-invalid

          [5]css-media-vars: https://propjockey.github.io/css-media-vars/

          [6]CSS 鍵盤記錄器: https://github.com/maxchehab/CSS-Keylogging

          [7]augmented-ui: http://augmented-ui.com/

          [8]掃雷: https://github.com/propjockey/css-sweeper

          [9]augmented-ui: https://github.com/propjockey/augmented-ui

          [10]css-media-vars: https://github.com/propjockey/css-media-vars

          [11]css-sweeper: https://github.com/propjockey/css-sweeper

          1. JavaScript 重溫系列(22篇全)
          2. ECMAScript 重溫系列(10篇全)
          3. JavaScript設計模式 重溫系列(9篇全)
          4. 正則 / 框架 / 算法等 重溫系列(16篇全)
          5. Webpack4 入門(上)|| Webpack4 入門(下)
          6. MobX 入門(上) ||  MobX 入門(下)
          7. 100+篇原創(chuàng)系列匯總

          回復“加群”與大佬們一起交流學習~

          點擊“閱讀原文”查看 100+ 篇原創(chuàng)文章

          瀏覽 34
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美A片久久 | 日本黄色电影网站视频 | 亚洲国产精品成人综合久 | 欧洲熟妇的性久久久久久 | 免费在线黄片 |