CSS的將來已來

前言

最近據說TypeScript3.7添加了對Optional Chaining的支持,而後就想着給魚頭的腳手架ying-template的TS版本升級,而後在命令行發現這樣的一句信息:javascript

'postcss-cssnext' 已經被 'postcss-preset-env'代替了。詳情請查看 https://moox.io/blog/deprecat...

其實魚頭的腳手架裏早就把postcss-cssnext換成了postcss-preset-env,不過一直沒刪,可是看到這句話以後,處於好奇,就去翻了翻PostCSS的官網,而後又思考了下這些年CSS的發展歷程,遂有這篇文章的出爐。css

淺談現代化的CSS

從1997年 CSS1.0 發佈到現在,從最開始只支持簡單的文字排版到現在已經能夠作出酷炫的3D動畫,CSS已經走過了22個年頭,其發展如圖所示:html

image

圖片來自[MDN]前端

隨着互聯網的發展,人們對網頁的要求已是從只要展現圖文就好變成了各類交互跟視覺效果都須要有着更多的體驗要求。CSS爲此也是不斷的更新着。java

隨着web業務日益複雜化和多元化,前端開發也從單純的web page轉變成web app,在此也誕生了「前端工程化」的概念,一個完備的web app每每會很大很複雜,甚至會有不少人共同維護,以往的拼頁面,寫jQuery已是不足以支撐現代的需求。一樣的,CSS也是如此,再也不是內聯寫幾個marginpadding或者HTML一股腦引入幾個CSS就足夠的,並且因爲人員配置的增多,不一樣的開發,命名習慣,樣式是否會衝突也是必需要考慮的。webpack

除了工程問題,還有就是CSS與瀏覽器之間的關係也是咱們不得不考慮的,雖然CSS發展的很快,可是瀏覽器對CSS新特性支持的進度確實很是緩慢的。因此雖然某些屬性已經推出了不少年,可是也每每由於瀏覽器的緣由而沒法進行大規模的使用。git

雖然在實際開發過程當中,CSS有着這樣那樣讓人沒法忽略的問題,可是「方法總比困難多」,在前端界也有許多熱心的大牛們在嘗試着解決這些問題。此次讓魚頭與你們一塊兒分享下這些與CSS相關的技巧與方法。github

最初的CSS模塊化 —— CSS命名規則

命名一直是開發者比較頭疼的問題,在前端裏,除了JS各類變量的命名,還有元素class的命名,雖然咱們能夠隨意起名,願意的話甚至可使用 .a .b .c等無心義的規則來命名,可是若是是一個長期的,大型的或多人協做的項目裏這麼命名,恐怕容易被人胖揍。此次咱們來分享下業界經常使用的用來防捱揍的命名規則。

OOCSS(Object-Oriented CSS)

OOCSS有兩個編寫原則:web

  • 結構與樣式分離
  • 容器與內容分離

咱們來看看官網的一個例子:typescript

image

<div class="mod grab"> 
    <b class="top">
        <b class="tl"></b>
        <b class="tr"></b>
    </b> 
    <div class="inner">
        <div class="hd">
            <h3>grab</h3>
        </div>
        <div class="bd">
            <p>Body</p>
        </div>
    </div>
    <b class="bottom">
        <b class="bl"></b>
        <b class="br"></b>
    </b> 
</div>

在這裏.mod是父類,全部的類都是繼承自它,.grab即是子類。

至於.top.innerbottom,顧名思義就是不一樣位置的子盒子。

這裏是以「容器」爲命名法則。

BEM

BEM 是塊(Block)、 元素(Element)、修飾符( Modifier)的單詞集合。

在選擇器中,咱們用如下三種符號來表示以上內容

  • - 中劃線 :僅做爲連字符使用,表示某個塊或者某個子元素的多單詞之間的鏈接記號。
  • __ 雙下劃線:雙下劃線用來鏈接塊和塊的子元素
  • _ 單下劃線:單下劃線用來描述一個塊或者塊的子元素的一種狀態

就像這樣:type-block__element_modifier

官網的例子以下:

image

<style>
    .button {
        display: inline-block;
        border-radius: 3px;
        padding: 7px 12px;
        border: 1px solid #D5D5D5;
        background-image: linear-gradient(#EEE, #DDD);
        font: 700 13px/18px Helvetica, arial;
    }
    .button--state-success {
        color: #FFF;
        background: #569E3D linear-gradient(#79D858, #569E3D) repeat-x;
        border-color: #4A993E;
    }
    .button--state-danger {
        color: #900;
    }
</style>
<button class="button">
    Normal button
</button>
<button class="button button--state-success">
    Success button
</button>
<button class="button button--state-danger">
    Danger button
</button>

SMACSS

SMACSS,一個長得很像OOCSS的規則。

核心只有如下6個:

  • Base:頁面的基本樣式命名規則
  • Layout:佈局命名規則
  • Module:模塊規命名規則
  • State:狀態命名規則
  • Theme:主題命名規則
  • Changing State:可變狀態的命名規則

修飾符是--,子模塊是__

官網的例子以下:

image

<style>
    #header { … }
    #primarynav { … }
    #maincontent { … }
</style>
<div id="header"></div>
<div id="primarynav"></div>
<div id="maincontent"></div>

爲CSS賦能 —— 預處理器

CSS 預處理器是一個能讓你經過預處理器本身獨有的語法來生成CSS的程序。市面上有不少CSS預處理器可供選擇,且絕大多數CSS預處理器會增長一些原生CSS不具有的特性,例如代碼混合,嵌套選擇器,繼承選擇器等。這些特性讓CSS的結構更加具備可讀性且易於維護。

sass

image

sass是誕生最先,也是世界上最成熟、最穩定、最強大的專業級CSS擴展語言!(官網說的(O_o)?? )

sass可用使用變量,嵌套規則,混合器,繼承等編程語言纔有的概念,代碼例子以下:

$nav-color: #F90;
nav {
  $width: 100px;
  width: $width;
  color: $nav-color;
}

//編譯後

nav {
  width: 100px;
  color: #F90;
}

less

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-DgwxMfHk-1573627304548)(http://lesscss.org/public/img...)]

Less 是一門 CSS 預處理語言,它擴展了 CSS 語言,增長了變量、Mixin、函數等特性,使 CSS 更易維護和擴展。

代碼例子以下:

@base: #f938ab;

.box-shadow(@style, @c) when (iscolor(@c)) {
  -webkit-box-shadow: @style @c;
  box-shadow:         @style @c;
}
.box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
  .box-shadow(@style, rgba(0, 0, 0, @alpha));
}
.box {
  color: saturate(@base, 5%);
  border-color: lighten(@base, 30%);
  div { .box-shadow(0 0 5px, 30%) }
}

// 編譯後
.box {
  color: #fe33ac;
  border-color: #fdcdea;
}
.box div {
  -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
}

stylus

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tCdAdqND-1573627304550)(https://timgsa.baidu.com/timg...]

Stylus,富於表現力、動態的、健壯的 CSS

代碼例子以下:

body
  font 12px Helvetica, Arial, sans-serif

a.button
  border-radius 5px

徹底不須要{} : ;的預處理器,我的是特別不喜歡這種寫法,可是對於不少喜歡簡潔的開發者來講,這確實很是好的編寫方式

如魔法師通常的存在 —— CSS Houdini

有點時候眼看CSS出來新的屬性,可是由於瀏覽器兼容的問題,因此每每是隻能看而不能用,即使有的屬性能夠用,但也由於各瀏覽器的現實狀況而存在乎想不到的BUG,那麼這就意味着一個屬性出來以後咱們要等到5年甚至更久以後才能使用嗎?都9012年了耶?

固然不是,接下來咱們能夠了解一下這個如魔法師通常的存在 —— CSS Houdini

CSS Houdini是什麼?

CSS Houdini是一組底層API,它們公開了CSS引擎的各個部分,從而使開發者能夠經過這組API來擴展CSS。它讓開發者擁有了直接訪問CSSOM的能力,開發者能夠經過這組API來編寫瀏覽器可解析的CSS代碼,這讓開發者能夠在不須要等待瀏覽器的實現的前提下實現本身想要的CSS功能。

image

[圖片來自:https://www.qed42.com/blog/bu...]

如上所示,不一樣的API所對應的就是瀏覽器不一樣的渲染環節,用時下流行的概念來解釋就是瀏覽器加載時不一樣生命週期的鉤子函數。

簡單來講,CSS Houdini就是JS IN CSS,niubility ..

CSS Houdini是怎麼工做的?

咱們可訪問的7個API以下:

  1. Typed OM API
  2. Properties & Values API
  3. Paint API
  4. Layout API
  5. Animation worklet
  6. Parser API
  7. Font Metrics API

Mmmm,雖然是有7個API(Houdini drafts上還有一些),但瀏覽器實際的支持狀況實際上是這樣的:

image

[圖片來自:https://ishoudinireadyyet.com/]

CSS Houdini的工做流程以下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5EJvSHWB-1573627304556)(https://www.qed42.com/sites/d...]

[圖片來自:https://www.qed42.com/blog/bu...]

  1. 鉤子進入渲染的進程中
  2. JS是這個鉤子的核心
  3. 使用JS的Typed OM,能夠掛載自定義的屬性,繪製圖形,佈局以及動畫
  4. 還有其餘兩個API:Parser API 和 Font Metrics API。它們用於註冊CSS相關的新事物

一些示例

本篇不打算細講CSS Houdini,因此不會畫出全部的DEMO,有興趣的能夠查看底部的「資料來源」,從而獲取更加詳細的信息。

Typed OM

<style>
    * {
        margin: 0;
        padding: 0;
    }
    .box {
        background: linear-gradient(to right, #2c3e50, #4ca1af);
    }
</style>
<div class="box" id="box"></div>
<script>
    'use strict'
    box.attributeStyleMap.set('width', CSS.px(200))
    box.attributeStyleMap.set('height', CSS.px(200))
    const [x, y] = 'width,height'
    .split(',')
    .map(val => Number.parseInt(box.computedStyleMap().get(val)))
    box.attributeStyleMap.set('transform', new CSSTranslate(CSS.px(x), CSS.px(y)))
    console.log(box.computedStyleMap().get('transform'))
    console.log(window.getComputedStyle(box, null)['transform'])
</script>

image

上面就是Typed OM的示例,這裏值得一提的就是,若是咱們用getComputedStyle去獲取transform的值,最終結果是個矩陣,這其實不太方便咱們作二次操做,可是用Typed OM的JS API computedStyleMap,去取的結果就是一個具體屬性的集合,這是很是有利於咱們進行二次操做的。

Paint API

Paint API就是容許你例如Canvas的屬性來編寫CSS樣式,使用方法也很簡單,咱們能夠看看https://slides.iamvdo.me/waq1...上的示例

首先咱們新建個文件叫registerPaint.js,在裏面寫下如下代碼:

registerPaint('circle-ripple', class {
  static get inputProperties() { return [ '--circle-color',
    '--circle-radius', '--circle-x', '--circle-y'
  ]}
  paint(ctx, geom, props, args) {
    const x = props.get('--circle-x').value;
    const y = props.get('--circle-y').value;
    const radius = props.get('--circle-radius').value;
  }
}

而後再新建一個index.html,而且在JS代碼裏註冊上面寫好的registerPaint.js,方式以下:CSS.paintWorklet.addModule('registerPaint.js');

具體代碼以下:

<style>
    .el {
          --circle-radius: 0;
          --circle-color: deepskyblue;
          background-image: paint(circle-ripple);
    }
    .el.animating {
          transition: --circle-radius 1s,
                      --circle-color 1s;
          --circle-radius: 300;
          --circle-color: transparent;
    }
</style>
<div class="el" id="el"></div>
<script>
    'use strict'
    CSS.paintWorklet.addModule('registerPaint.js');
    el.addEventListener('click', e => {
          el.classList.add('animating');
          el.attributeStyleMap.set('--circle-x', e.offsetX);
          el.attributeStyleMap.set('--circle-y', e.offsetY);
    });
</script>

因此咱們有如下的效果:

image

CSS屆的Babel —— PostCSS

說到底CSS Houdini其實也只是JS IN CSS,並非純正的CSS,那麼對於一些新的CSS屬性,咱們相用的話,真的還得等5年後嗎?還有即使是有各類工具,可是像一些兼容性寫法,廠商前綴,循環,原生CSS也沒有,咱們不是還得須要依賴CSS預處理器嗎?

其實也不是,這時候咱們能夠利用CSS屆的Babel —— PostCSS

PostCSS是什麼?

簡單來講PostCSS就是可讓開發者使用JS來處理CSS的處理器,它分了如下5大類功能:

加強代碼的可讀性

利用從 Can I Use 網站獲取的數據爲 CSS 規則添加特定廠商的前綴。Autoprefixer 自動獲取瀏覽器的流行度和可以支持的屬性,並根據這些數據幫你自動爲 CSS 規則添加前綴。

例如咱們輸入如下代碼:

:fullscreen {
}

那麼就會輸出:

:-webkit-:full-screen {
}
:-moz-:full-screen {
}
:full-screen {
}

將將來的 CSS 特性帶到今天!

PostCSS Preset Env 幫你將現代 CSS 語法轉換成大多數瀏覽器都能理解的東西,根據你的目標瀏覽器或運行時環境來肯定你須要的 polyfills,基於 cssdb 實現

例如咱們輸入如下代碼:

@custom-media --med (width <= 50rem);

@media (--med) {
  a { 
    &:hover {
      color: color-mod(black alpha(54%));
    }
  }
}

就會輸出:

@media (max-width: 50rem) {
  a:hover  { 
    color: rgba(0, 0, 0, 0.54);
  }
}

終結全局 CSS

CSS 模塊 就是說你永遠不用擔憂命名太大衆化而形成衝突太普通,只要用最有意義的名字就好了。

例如咱們輸入如下代碼:

.name {
  color: gray;
}

就會輸出:

.Logo__name__SVK0g {
  color: gray;
}

避免 CSS 代碼中的錯誤

經過使用 stylelint 強化一致性約定並避免樣式表中的錯誤,stylelint 是一個現代化 CSS 代碼檢查工具。它支持最新的 CSS 語法,包括相似 CSS 的語法,例如 SCSS 。

例如咱們輸入如下代碼:

a { 
  color: #d3;
}

那麼控制檯會拋出錯誤:

app.css
2:10 Invalid hex color

強大的網格系統

LostGrid 利用 calc() 和你所定義的分割方式來建立網格系統,無需傳遞大量參數。

例如咱們輸入如下代碼:

div {
  lost-column: 1/3 
}

就會輸出:

div {
  width: calc(99.9% * 1/3 -  
  (30px - 30px * 1/3)); 
}
div:nth-child(1n) {
  float: left; 
  margin-right: 30px; 
  clear: none; 
}
div:last-child {
  margin-right: 0; 
}
div:nth-child(3n) {
  margin-right: 0; 
  float: right; 
}
div:nth-child(3n + 1) {
  clear: both; 
}

可窺探的將來 —— cssdb

cssdb是postcss-preset-env的實現基準,主要就是CSS的新功能功能及這些功能從提出到成爲標準時所在的進程。

cssdb跟ecma同樣,對新屬性分了不一樣的進程,具體的進程以下:

  1. Stage 0:腦殼風暴階段。高度不穩定,可能會發生變化。
  2. Stage 1:實驗階段。也很是不穩定,可能會發生變化,可是該提案已獲得W3C成員的承認。
  3. Stage 2:認可階段。高度不穩定而且可能會發生變化,可是正在積極研究中。
  4. Stage3:擁抱階段。穩定且變化不大,此功能可能會成爲標準。
  5. Stage4:標準階段。最終的解決方案,全部主流瀏覽器都支持。

這就是postcss-preset-env依賴的實現基準,那麼若是咱們想要在咱們的代碼裏使用這些Stage,該怎麼作呢?

以個人腳手架ying-template爲例,咱們來查看在webpack中的實際配置:

首先咱們先安裝postcss以及其相應的插件:

npm install postcss postcss-loader postcss-preset-env postcss-nesting --save-dev

而後咱們在webpack的config配置module中輸入如下配置:

module: {
    rules: [
        {
            test: /\.css$/,
            include,
            exclude,
            use: [/* 你其它的loader */ 'postcss-loader']
        }
    ]
}

而後在根目錄新建一個postcss.config.js

const postcssConfig = {
    plugins: {
        precss: {},
        'postcss-preset-env': {
            browsers: 'last 2 versions', // 瀏覽器兼容的版本
            stage: 3 // 你用的屬性所在的階段
        },
        'postcss-nesting': {} // 這裏就是你所使用的插件
    }
};
module.exports = postcssConfig

這樣就完成了,若是想看完整的配置,能夠clone個人腳手架:https://github.com/KRISACHAN/...

(這是個多頁面的webpack4腳手架,集成了babel 7,precss 4,typescript3.7,karma以及eslint等現代前端開發所需經常使用的東西,有興趣的能夠去看看。)

咱們能夠經過https://preset-env.cssdb.org/...這個網站來查看具體的編譯結果。

編譯結果圖以下:

image

是否是很是神奇呢?

後話

隨着前端工程的普及,某E瀏覽器的沒落,CSS的發展可謂是一日千里,近日也有一些數學屬性的提案在發起,之後會發展成什麼樣,沒人能夠知道。只是總的來講,CSS的將來是一片光明的。本文簡單分享了一些現代化的CSS知識,經過這些知識,咱們很容易就能寫出完備且現代化的CSS代碼,可以給創造出更多的效益,但願你們能夠積極地用起這些知識,並對CSS能夠有更多的思考以及想象。

CSS,將來可期

資料來源

  1. https://developer.mozilla.org...
  2. http://oocss.org/
  3. http://getbem.com/
  4. http://smacss.com/
  5. https://sass-lang.com/
  6. http://lesscss.org/
  7. http://stylus-lang.com/
  8. https://blog.techbridge.cc/20...
  9. https://www.smashingmagazine....
  10. https://slides.iamvdo.me/waq1...
  11. https://www.qed42.com/blog/bu...
  12. https://www.postcss.com.cn/
  13. https://cssdb.org/#staging-pr...
  14. https://s0dev0to.icopy.site/a...

若是你喜歡探討技術,或者對本文有任何的意見或建議,很是歡迎加魚頭微信好友一塊兒探討,固然,魚頭也很是但願能跟你一塊兒聊生活,聊愛好,談天說地。
魚頭的微信號是:krisChans95
也能夠掃碼添加好友,備註「SF」就行
https://fish-pond-1253945200.cos.ap-guangzhou.myqcloud.com/img/base/wx-qrcode1.jpg

相關文章
相關標籤/搜索