天天看點

剖析CSS-Tricks,為我所用

CSS-Tricks網站

是一個非常優秀的網站,特别對于CSSer而言,該網站不斷的在更新一些優秀的教程和技巧,為前端社群做出了具大的貢獻。她一直是我的偶像,也是我學習的榜樣,因為我從該網站上學到了很多新技術,讓我在CSS方面的眼界擴充的更大。今年1月份改版之後,整個社交媒體的響應非常的熱烈,很多人都為新版贊賞。而我這次參加

中國第五屆CSS Conf大會

之前和 @裕波 聊過,該和社群的同學聊什麼樣的話題呢?經過讨論下來,要不就聊聊CSS-Tricks網站這次改版運用的一些新特性,這些新特性又為使用者體驗帶來什麼樣的改變,甚至為前端開發者又帶來什麼樣的改變?是以借此機會,以我自己的視角來聊聊相關的話題。

CSS-Trick 設計改版本的變更

剖析CSS-Tricks,為我所用

時至今日,CSS-Tricks網站的改版已經

經曆了

17

個版本的變更

,每個版本都有其獨之處,特别是今年(2019年1月釋出的版本)在整個前端社群得到熱烈的反響,不管是在Twitter還是Facebook針對改版後的讨論都非常地多。先上一下最早釋出版本的視覺截圖:

剖析CSS-Tricks,為我所用
你可以現在通路的版本和所看到的最初版本略有不同,因為該設計(版本)一直在不斷的更新。

當然從設計稿上看,隻能看出來設計稿和以往版本有何不同的外觀效果,但做為技術人員,還是喜歡看看新版的設計運用了什麼樣的新特性,這些新特性又給使用者和我們帶來什麼樣的變化。那麼接下來,我們一起來聊了新版用了哪些CSS方面的特性。

V17. 版本技術亮點

前面也提到了,接下來要聊的技術亮點是有關于CSS的,在新版中運用的到技術亮點,主要總結起來有以下幾點:

  • SVG的使用
  • 滾動特性
  • 自定義屬性
  • Web Layout
  • 混合模式和濾鏡
  • 其他(^_^)
這僅僅是從我自己的角度出發的,或許有很多遺漏的,如果您有更多的見解,歡迎在下面的評論中與我們一起讨論和分享。

SVG

對于SVG而言,她是一套獨立而又成熟的體系,也有自己的相關規範(Scalable Vecgtor Graphics 2),即

SVG2

。雖然該規範已經存在很久了,但很多有關于SVG相關的特性在不同的浏覽器中得到的支援度也是有所不一緻的。特别是

SVG中的漸變

濾鏡相關的特性

。不過,随着技術的革新,在Web的應用當中SVG的使用越來越多,特别是SVG 圖示相關的方面的運用。

在CSS-Tricks新版中,好幾個地方都使用了SVG的技術,特别是SVG的圖示。比如:

剖析CSS-Tricks,為我所用

可以說,站上有關于圖示都是通過SVG來完成的,而且采用的是SVG Sprites相關的技術。而且該方面的技術也算不上是什麼新技術,早久之前就有相關方面的介紹,比如:

Web自1989年到2019年也算是走過了30年的曆程了,那麼Web上面有關于圖示的使用也經曆了相應的發展:

剖析CSS-Tricks,為我所用
  • 最早通過

    <img>

    标簽來引用圖示(每個圖示一個檔案)
  • 為了節省請求,提出了Sprites的概念,即 将多個圖示合并在一起,使用一個圖檔檔案 ,借助

    background

    相關的屬性來實作圖示
  • 圖檔畢竟是位圖,面對多種裝置終端,或者說更易于控制圖示顔色和大小,開始在使用 Icon Font 來制作Web圖示
  • 當然,字型圖示是解決了不少問題,但每次針對不同的圖示的使用,需要自定義字型,也要加載相應的字型檔案,相應的也帶了一定的問題,比如說跨域問題,字型加載問題
  • 随着SVG的支援力度越來越強,大家開始在思考SVG,使用SVG來制作圖示。該技術能解決我們前面碰到的大部分問題,特别是在而對衆多終端裝置的時候,它的優勢越發明顯
  • SVG和

    img

    有點類似,我們也可以借助

    <symbol>

    标簽和

    <use>

    标簽,将所有的SVG圖示拼接在一起,有點類似于Sprites的技術,隻不過在此稱為SVG Sprites

有關于這方面更詳細的介紹,可以閱讀《

Web中的圖示

》一文。

既然SVG Sprites有這麼的優勢,那麼在Web中使用也就理所當然。估計也正因為這些原因,CSS-Tricks網站也使用了該技術。使用該技術并不複雜,比如:

<!-- HTML -->
<svg width="0" height="0" display="none" xmlns="http://www.w3.org/2000/svg">
    <symbol id="half-circle" viewBox="0 0 106 57">...</symbol>
    <!-- .... -->
    <symbol id="icon-burger" viewBox="0 0 24 24">...</symbol>
</svg>
           

SVG Sprites和img Sprites有所不同,SVG Sprites就是一些代碼(類似于HTML一樣),估計沒有接觸過的同學會問,SVG Sprites對應的代碼怎麼來擷取呢?其實很簡單,可以借助一些設計軟體來完成,比如Sketch。當然也可以使用一些建構工具,比如說

svg-sprite

。有了這個之後,在該使用的地方,使用

<use>

标簽,指定

<symbol>

中相應的

id

值即可,比如:

<svg class="icon-nav-articles" width="26px" height="26px">
    <use xlink:href="#icon-nav-articles"></use>
</svg>
           

使用SVG的圖示還有一優勢,我們可以在CSS中直接通過代碼來控制圖示的顔色:

.site-header .main-nav .main-sections>li>a>svg {
    // ...
    fill: none;
    stroke-width: 2;
    stroke: #c2c2c2;
}
.site-header .main-nav:hover>ul>li:nth-child(1) svg {
    stroke: #ff8a00;
}
           

是不是很簡單。如果你是使用類似像Vue或React之類的JavaScript架構之類的,還可以将該特性封裝成一個元件,隻需要将需要使用的圖示存入到指定的位置,借助Webpack建構能力就可以自動生成相應的SVG Sprites代碼,使用封裝好的元件,在另何需要使用的地方調用即可。比如《

如何在Vue項目中使用SVG Icon

》一文所介紹的,在Vue中使用SVG圖示就非常的容易。

在新版的CSS-Tricks中,除了使用了SVG的圖示之外,還使用了SVG的漸變,制作一些漸變的效果。不過這裡就不做過多的闡述,感興趣的同學可以自己的探讨。

有關于SVG更多的内容, 可以點選這裡進行了解

有關于容器滾動方面的CSS新特性其實有很多個,比如:

  • 自定義滾動條的外觀
  • scroll-behavior

    指容容器滾動行為,讓滾動效果更絲滑
  • overscroll-behavior

    優化滾動邊界,特别是可以幫助我們滾動的穿透
  • 滾動捕捉

早前在《

改變使用者體驗的滾動新特性

》一文針對滾動特性帶來的使用者體驗改變做過詳細的探讨。而在CSS-Tricks新版中,運用了自定義動條的外觀和滾動捕捉的特性。

embed: cards.mp4

先來看一下自定義滾動條。

在不同的系統和平台下,滾動條的外觀都是有所不同的:

剖析CSS-Tricks,為我所用

雖然不同的平台上滾動條的外觀有所不同,但它們對應的關鍵部分是一樣的:

剖析CSS-Tricks,為我所用

在CSS中,我們可以使用

-webkit-scrollbar

來自定義滾動條的外觀。該屬性提供了七個僞元素:

  • ::-webkit-scrollbar

    :整個滾動條
  • ::-webkit-scrollbar-button

    :滾動條上的按鈕(下下箭頭)
  • ::-webkit-scrollbar-thumb

    :滾動條上的滾動滑塊
  • ::-webkit-scrollbar-track

    :滾動條軌道
  • ::-webkit-scrollbar-track-piece

    :滾動條沒有滑塊的軌道部分
  • ::-webkit-scrollbar-corner

    :當同時有垂直和水準滾動條時交彙的部分
  • ::-webkit-resizer

    :某些元素的交彙部分的部分樣式(類似

    textarea

    的可拖動按鈕)

比如上面的視訊中,整個頁面的滾動條外觀就是自定義的,在

html

中使用

-webkit-scrollbar

相應的僞元素來完成的:

html {
    --maxWidth:1284px;scrollbar-color: linear-gradient(to bottom,#ff8a00,#da1b60);
    scrollbar-width: 30px;
    background: #100e17;
    color: #fff;
    overflow-x: hidden
}

html::-webkit-scrollbar {
    width: 30px;
    height: 30px
}

html::-webkit-scrollbar-thumb {
    background: -webkit-gradient(linear,left top,left bottom,from(#ff8a00),to(#da1b60));
    background: linear-gradient(to bottom,#ff8a00,#da1b60);
    border-radius: 30px;
    -webkit-box-shadow: inset 2px 2px 2px rgba(255,255,255,.25),inset -2px -2px 2px rgba(0,0,0,.25);
    box-shadow: inset 2px 2px 2px rgba(255,255,255,.25),inset -2px -2px 2px rgba(0,0,0,.25)
}

html::-webkit-scrollbar-track {
    background: linear-gradient(to right,#201c29,#201c29 1px,#100e17 1px,#100e17)
}
           

是不是很簡單。通過這幾個僞元素,可以實作你自己喜歡的滾動條外觀效果,比如下面這個示例:

剖析CSS-Tricks,為我所用
線上Demo可以點選這裡檢視

另外,上面的視訊還展示了另一個滾動特特,即滾動捕捉。該特性可以為我們提供一個流式精确的滾動體驗。比如

Swiper的效果

剖析CSS-Tricks,為我所用

對于這樣的效果,我們都想為觸控以及輸入裝置的使用者提供一個流式、精确的滾動體驗。而這樣的效果,被稱為Scroll Snap效果,而早前實作類似的效果需要借助JavaScript庫來完成。如今可以使用

CSS Scroll Snap Points

來實作。

CSS Scroll Snap Points工作原理很簡單:

通過在

x

以及

y

軸上定義“捕捉”來控制滾動容器的滾動行為。當使用者在水準或者垂直方向滾動時,利用捕捉點,滾動容器會捕捉到内容區域的某一點。

Scroll Snap Points主要提供了以下幾個屬性:

  • scroll-snap-type

    :定義在滾動容器中的一個捕捉點如何被嚴格的執行
  • scroll-snap-type-x

    :定義在滾動容器中水準軸上捕捉點如何被嚴格的執行
  • scroll-snap-type-y

    :定義在滾動容器中垂直軸上捕捉點如何被嚴格的執行
  • scroll-snap-coordinate

    :結合元素的最近的祖先元素滾動容器的

    scroll-snap-destination

    定義的軸,定義了元素中

    x

    y

    坐标偏移的位置。如果元素已經變型,捕捉坐标也以相同的方式進行變型,為了使元素的捕捉點向元素一樣被顯示
  • scroll-snap-destination

    :定義滾動容器的可視化

    viewport

    中元素捕捉點的

    x

    y

    坐标位置
  • scroll-snap-points-x

    :定義滾動容器中内容的捕捉點的水準位置
  • scroll-snap-points-y

    :定義滾動容器中内容的捕捉點的垂直位置
  • scroll-snap-align

    :元素相對于其父元素滾動容器的對齊方式。它具有兩個值

    x

    y

    。如果你隻使用其中的一個,另外一個值預設相同
  • scroll-snap-padding

    :與視覺視窗的滾動容器有關。工作原理也相近與正常的内邊距,值設定一緻。此屬性具有動畫效果,是以如果你想要對齊捕捉點進行滾動,這将是一個很好的而選擇

随着技術的變更,該特性相關的屬性也發生了相應的變化:

剖析CSS-Tricks,為我所用

其中

scroll-snap-align

scroll-snap-destination

scroll-snap-coordinate

scroll-snap-type

是其中較為重要的幾個屬性,簡單的用下圖來向大家描述:

剖析CSS-Tricks,為我所用

比如CSS-Tricks上就使用了相關的特性:

剖析CSS-Tricks,為我所用

該特性如果應用得好,效果會更有意思,比如下面這個示例:

剖析CSS-Tricks,為我所用

CSS自定義屬性

對于很多前端同學可能并沒有接觸過,甚至沒有聽說過,但如果說CSS的變量,估計就很多同學有聽說過。但這裡再次強調,我們應該糾正這樣的說法:

CSS沒有變量,沒有變量,沒有變量;隻有自定義屬性,隻有自定義屬性,隻有自定義屬性!

CSS自定義屬性在W3C規範是獨立的一個子產品,目前是

Level 1版本(CSS Custom Properties for Cascading Variables Module Level)

,另外還有一個

Level 2版本

(目前處于ED階段)。該特性雖然在CSS中的曆史不長,但很多開發者都非常這個特性,在Youtuebe和Facebook頁面上都可以看到它們的影子:

剖析CSS-Tricks,為我所用

在CSS-Tricks這次改版後的代碼中,同樣也看到了CSS自定義屬性:

剖析CSS-Tricks,為我所用

而且在網際網路上,有關于CSS 自定義屬性的教程和案例特别的多。這裡推薦大家閱讀@Michael Riethmuller在SmashingMagazine上的一篇博文《

A Strategy Guide To CSS Custom Properties

》(注,

中文可以點選這裡閱讀

)。如果你從未接觸過CSS自定義屬性的話,我建議你先花點時間閱讀《

是時候開始使用自定義屬性

回到我們的主題中來,CSS 自定義屬性使用非常的簡單,但就是這些簡單的使用可以幫助我們建構出非常優秀的東東出來。當然,還能讓我們更好的編寫和維護CSS代碼。接下來通過幾個小示例來向大家簡單的介紹一下。

為了讓新接觸的同學對CSS自定義屬性有點概念或印象,簡單的來看一下他的基本使用。當然,如果接觸過CSS處理器的同學,過渡過來還是非常快的。比如你曾經使用過Sass或LESS這樣的處理器,你編寫代碼的時候可能會像下面這樣:

/* SCSS */
$color: red;
a {
    color: $color;
}

/* LESS */
@color: red;
a {
    color: @color;
}
           

而CSS自定義屬性的聲明也非常的類似,先用

--properyName: value

這樣的形式來聲明一個自定義屬性,然後通過

var()

函數來調用:

:root {
    --color: red;
}

a {
    color: var(--color)
}
           

在CSS自定義屬性中,除了可以在

:root{}

中聲明任何你想要的自定義屬性,還可以在CSS的任何選擇器中聲明,隻不過使用的範圍有所差別(後面會介紹到);另外

var()

函數調用已聲明好的自定義屬性時還可以通過其第二個參數,給自定義屬性提供一個備用值:

a {
    color: var(--color, black)
}
           

是不是非常的簡單,但這裡我還是需要再次強調一下:

它是自定義屬性,是屬性,而不是變量。

接下來,從另外幾個方面來闡述一下CSS自定義屬性和CSS處理器有何不同之處,另外它除了這些還具備一些什麼樣的優勢。首先要說的是:

動态 vs. 靜态

CSS處理器器運作機制整個過程用下圖應該可以很清楚的說清楚:

剖析CSS-Tricks,為我所用

也就是說,最終在頁面上給大家呈現的依舊是CSS代碼。也就是說,CSS處理器中的變量或其他功能僅僅是在編譯的時候生效,它是一種靜态的。而CSS自定義屬性卻不一樣,他是一種動态的,你在用戶端運作時就可以做出相應的改變。比如你想在不同的視窗中運用不同的

padding

值:

// SCSS
$gutter: 1em;

@media (min-width: 30em) {
    $gutter: 2em; /* 無效的 */
}

.container {
    padding: $gutter;
}
           

使用過SCSS的同學,或許一眼就看出來了,在

@media

中的

$gutter

并沒有生效,最後編譯出來的CSS代碼中,你隻能找到:

.container {
    paddidng: 1em;
}
           

你的視窗(浏覽器寬度)變化,它始終都是

1em

。這就是所謂的 靜态 (處理器無法在用戶端動态編譯)。當然,如果你添加了JavaScript來處理是另外一回事,這一塊不做深入的探讨。接着來看CSS自定義屬性,所起的作用是完全不一樣的:

:root {
    --gutter: 1em;
}

@media (min-width: 30em) {
    :root {
        --gutter: 2em;
    }
}

.container {
    padding: var(--gutter)
}
           

如果你自己親手撸了上面的代碼,當你改變浏覽器寬度的時候,你會發現

.container

padding

會發生相應的變化。也就是說,CSS自定義屬性是動态的,在用戶端中可以動态響應。除此之外,CSS自定義屬性還可以通過JavaScript來動态改變其值,比如:

:root {
    --mouse-x: 0px;
    --mouse-y: 0px;
}

.move {
    left: var(--mouse-x);
    top: var(--mouse-y);
}

let root = document.documentElement;

root.addEventListener('mouse', e => {
    root.style.setProperty('--mouse-x', e.clientX + 'px');
    root.style.setProperty('--mouse-y', e.clientY + 'px');
})
           

這樣的話,你能做的事情就更多了。

級聯 和 繼承

級聯和繼承

在CSS中一個很重要的概念。在CSS自定義屬性中處理起來也相對容易一些,為了更好的有一個對比性,我們來看兩個簡單的示例。

// SCSS . 級聯
$font-size: 1em;

.user-setting-larger-text {
    $font-size: 1.5em; // 無效
}

body {
    font-size: $font-size
}

/ * CSS 自定義屬性 * /

:root {
    --font-size: 1em;
}

.user-setting-large-text {
    --font-size: 1.5em; /* 有效的 */
}

body {
    font-size: var(--font-size); 
}
           

上面的示例中,SCSS編譯出來的CSS代碼,

body

font-size

始終都是

1em

,哪怕是使用者顯式設定了

.user-setting-large-text

也是如此。但在CSS自定義屬性中卻不一樣,預設

body

font-size

值是

1em

,一旦

.user-setting-large-text

生效(比如說顯式在

body

中添加了這個類名或JavaScript給

body

添加了這個類名),那麼

body

font-size

值就變成了

1.5em

再來看一個繼承的示例。警告框的UI在Web頁面中也是常見的一種UI效果,很多時候我們希望某些元素的UI能繼承父元素的值(或在其基礎上做相應的計算),比如下面這樣的一個示例:

// SCSS . 繼承
$alert-color: red;
$alert-info-color: green;

.alert {
    background-color: $alert-color;

    &.info {
        background-color: $alert-info-color;
    }

    button {
        border-color: darken(background-color, 25%); // 不生效
    }
}

/ * CSS 自定義屬性 * 

.alert {
    --background-color: red;
}

.alert.info {
    --background-color: green;
}

.alert button {
    border-color: color-mod(var(--background-color), darken(25%)); / *生效* /
}
           

在SCSS中那段

darken(background-color, 25%)

是無效的,因為它無法繼承父元素的任何CSS屬性,但在CSS自定義屬性中卻可以。有關于這個示例,

@E0 大大針對換膚的一個答案中做過詳細的介紹

**color-mod()**

函數是 CSS Color Module Level 4 中的一部分,到目前還沒有浏覽器實作。有關于這方面更詳細的介紹,可以閱讀《 使用

color-mod()

函數修改顔色
》和《 CSS中的函數 》。另外 @Claudia Romano 的博文《 How to combine SASS color functions and CSS Variables 》中介紹了如何通過Sass和CSS自定義屬性的結合來實作類似

color-mod()

函數中部分功能。

全局 vs. 局部

這裡所說的是全局作用域和局部作用域,其實不管是CSS的處理器,還是CSS的處理器,甚至到現在的CSS自定義屬性中,都存有全局和局部的一說法。隻不過使用的場景會有所不同,前幾天@PPK在他的博文《

Scope in CSS

》中就有做過方面的讨論。這裡我們來看看,CSS自定義屬性中的全局和局部的一個對比,還是拿小示例來說吧:

<!-- HTML -->
<div> 我是什麼顔色?</div>
<p> 那我是什麼顔色? </p>
<div class="alert">
    我又是啥色?
    <p>那我呢?</p>
</div>

/ *CSS* /
:root {
    --color: red;
}
div {
    --color: yellow;
}
.alert {
    --color: blue;
}
* {
    color: var(--color);
}
           

先猜猜上面的每個元素對應的文本顔色是什麼顔色?

從示例中,可以看出來,分别在

:root

div

元素和

.alert

中聲明了一個相同的自定義屬性

--color

,不同的是值,分别為

red

yellow

blue

。事實上他們影響的面是有所不同的:

  • :root

    表示是在根元素上聲明的,

    --color: red

    ,将會影響所有的元素
  • div

    是一個标簽元素選擇器,其聲明的

    --color: yellow

    将會影響所有

    div

    元素以及他的後代元素
  • .alert

    是一個類選擇器,其聲明的

    --color: blue

    會影響類名為

    .alert

    的元素以及其後代碼元素

是以在第一個

div

的文本顔色是一個

yellow

(它覆寫了

:root

red

顔色);第一

p

的文本顔色是

red

(運用了

:root

red

色),第二個

div.alert

以及它的子元素

p

blue

.alert

blue

)。

是不是和你預想的結果一樣呢?

條件判斷

衆所周知,在CSS中到目前還沒有條件判斷相關的特性(或許将來會有)。不過我們可以借助CSS自定義屬性相關的特性配合

calc()

函數來實作一個類似于

if...else

這樣的條件判斷功能。假設有一個自定義屬性

--i

,當:

  • --i

    的值為

    1

    ,表示真(即打開)
  • --i

    ,表示假(即關閉)

比如,我們有一個

box

,根據條件來判斷它是否旋轉。當

--i:0

(假,不旋轉),反之

--i:1

(真,旋轉)。那麼我們就可以像下面這樣來完成:

:root {
    --i: 0;
}

.box {
    // 當 --i = 0 => calc(var(--i) * 30deg) = calc(0 * 30deg) = 0deg
    // 當 --i = 1 => calc(var(--i) * 30deg) = calc(1 * 30deg) = 30deg
    transform: rotate(calc(var(--i) * 30deg))
}

.box.rotate {
    --i: 1;
}
           

或者:

:root {
    --i: 1;
}

.box {
    // 當 --i = 0 => calc((1 - var(--i)) * 30deg) = calc((1 - 0) * 30deg) = calc(1 * 30deg) = 30deg
    // 當 --i = 0 => calc((1 - var(--i)) * 30deg) = calc((1 - 1) * 30deg) = calc(0 * 30deg) = 0deg
    transform: rotate(calc((1 - var(--i)) * 30deg))
}

.box.rotate {
    --i: 0;
}
           

整個效果如下圖:

剖析CSS-Tricks,為我所用

是不是非常有意思。

上面示範的是

1

之間的切換,其實還可以非零之間的切換,非零值之間的切換相對而言要更為複雜一些,這裡就不做過多的闡述,如果感興趣的話,可以閱讀 @Ana 的兩篇博文:

我把上面兩篇文章整合到一起,不喜歡閱讀英文的同學,可以閱讀《

如何通過CSS自定義屬性給CSS屬性切換提供開關

JS in CSS (CSS Houdini)

前面提到過,使用CSS自定義屬性的時候,可以通過JavaScript來操作自定義屬性的值。其實還可以更強大一點,如果你對CSS Houdini熟悉的話,可以借助其特特,直接在CSS的代碼中來操作CSS自定義屬性,比如下面這個@Una在CodePen上寫的示例:

<!-- HTML -->
<div contenteditable class="el">JS in CSS  </div>

<script>
    CSS.paintWorklet.addModule('/una/pen/xByaoB.js')
</script>

/* CSS */
.el {
    --scallopRadius: 10;
    --scallopColor: #8266ff;
    --scallopWeight: 4;
    --background-canvas: (ctx, geom) => {
        const radius = var(--scallopRadius);
        const scallopWeight = var(--scallopWeight);
        const color = `var(--scallopColor)`;
        const height = geom.height;
        const width = geom.width;

        ctx.lineWidth = scallopWeight;
        ctx.strokeStyle = color;
        
        const getSteps = (sizeVal) => {
            return Math.floor(sizeVal / (radius * 2) - 2)
        };

        const getOwnRadius = (sizeVal, otherRad) => {
            const steps = getSteps(sizeVal) + 1;
            const totalSpace = sizeVal - (radius * 2);
            const spaceTaken = steps * (radius * 2);
            let pixelsRemaining = totalSpace - spaceTaken;

            if (otherRad) {
                const radDif = otherRad - radius;
                pixelsRemaining = totalSpace - spaceTaken - radDif;
            };

            const newRadius = radius + ((pixelsRemaining / 2) / (steps + 1));
            return (newRadius);
        };

        const horizRadius = getOwnRadius(width, getOwnRadius(height));
        const vertRadius = getOwnRadius(height, getOwnRadius(width));

        for (let i = 0; i <= getSteps(width); i++) {
            ctx.beginPath();
            ctx.arc(horizRadius + horizRadius + (horizRadius * i * 2), horizRadius + (scallopWeight * 1) , horizRadius, 0, Math.PI, true);
            ctx.stroke();
        }

        for (let i = 0; i <= getSteps(width); i++) {
            ctx.beginPath();
            ctx.arc(horizRadius + horizRadius + (horizRadius * i * 2), height - horizRadius - (scallopWeight * 1), horizRadius, 0, Math.PI, false);
            ctx.stroke();
        }

        for (let i = 0; i <= getSteps(height); i++) {
            ctx.beginPath();
            ctx.arc(vertRadius + (scallopWeight * 1), vertRadius + vertRadius + (vertRadius * i * 2), vertRadius, Math.PI * 0.5,  Math.PI * 1.5, false);
            ctx.stroke();
        }

        for (let i = 0; i <= getSteps(height); i++) {
            ctx.beginPath();
            ctx.arc(width - vertRadius - (scallopWeight * 1), vertRadius + vertRadius + (vertRadius * i * 2), vertRadius, Math.PI * 0.5,  Math.PI * 1.5, true);
            ctx.stroke();
        }
    };
    background: paint(background-canvas); 
}

.el:after {
    --offset: 3px;
    content: '';
    width: 100%;
    height: 100%;
    position: absolute;
    top: var(--offset); 
    left: var(--offset);
    z-index: -1;
    filter: hue-rotate(50deg) opacity(0.4);
    background: paint(background-canvas); 
}
/* 其他CSS代碼略去 */

// JavaScript
if (typeof registerPaint !== 'undefined') {
    registerPaint('background-canvas', class {
        static get inputProperties() {
            return ['--background-canvas'];
        }
        paint(ctx, geom, properties) {
            eval(properties.get('--background-canvas').toString())(ctx, geom, properties);
        }
    })
}
           

整個效果如下:

剖析CSS-Tricks,為我所用

有了CSS自定義屬性之後,我們能做的事情會很多,也變得更為簡單。在動畫效果、圖表、主題切換之中都能看到CSS自定義屬性的身影。比如下面這個Loading的動效:

剖析CSS-Tricks,為我所用

比如@Keith Clark寫的圖表效果:

剖析CSS-Tricks,為我所用

@Stephanie寫的主題切換的效果:

剖析CSS-Tricks,為我所用
點選這裡檢視Demo效果

更多的示例就不一一列出來了,

在Codepne上搜尋CSS custom property關鍵詞,可以看到很多類似的Demo

聊完CSS自定義屬性,我們來接着聊Web布局。對于Web布局而言,前端就一直在探讨這方面的最優方式。早期的

table

布局,接着的

float

position

相關的布局,多列布局,Flexbox布局和Grid布局等。Flexbox和Grid的出現,Web布局的靈活性越來越高。

CSS-Tricks這次大膽的使用了CSS Grid布局:

剖析CSS-Tricks,為我所用

這個是整個網站較為複雜的部分,這個部分就采用了CSS Grid來做的布局。

.monthly-mixup {
    display:grid;
    grid-template-columns: repeat(6,1fr);
}
.mixup-card:nth-of-type(1) {
    grid-column: 5/6;
    grid-row: 1/2;
}
           

上面隻是CSS Grid的其中用法之一。其涉及到的知識點和相關術語還是很多的,如果你感興趣的話,

可以閱讀以前整理一些筆記和教程

平時和一些同學聊CSS Grid的時候,都認哥其強大之處,但很多同學都覺得CSS Grid的調試和使用都非常的累,甚至網格線讓大家感到困惑。事實上有這樣的困惑存在,但我們可以借助一些工具來幫助我們更好的克服或者說使用CSS Grid。比如Firefox浏覽器的網格調試器,就是一個很好的東東:

剖析CSS-Tricks,為我所用
有關于怎麼使用Firefox浏覽器的網格調試器相關的使用介紹可以閱讀《 使用Firefox 網格檢查器調試 CSS網格布局

上面的示例隻是CSS Grid中最基礎的功能,其實在CSS Grid中提供了很多強大的特性,比如:

  • fr

    機關,可以很好的幫助我們來 計算容器可用空間
  • repeat()

    函數,允許我們給網格多個列指定相同的值。它也接受兩個值:重複的次婁和重複的值
  • minmax()

    函數,能夠讓我們用最簡單的CSS控制網格軌道的大小,其包括一個最小值和一個最大值
  • auto-fill

    auto-fit

    ,配合

    repeat()

    函數使用,可以用來替代重複次數,可以根據每列的寬度靈活的改變網格的列數
  • max-content

    min-content

    ,可以根據單元格的内容來确定列的寬度
  • grid-suto-flow

    可以更好的讓CSS Grid布局時能自動排列

結合這些功能點,布局會變得更輕松。比如我們要實作一個響應式的布局,很多時候都會依賴于媒體查詢(

@media

)來處理,事實上,有了CSS Grid Layout之後,這一切變得更為簡單,

不需要依賴任何媒體查詢就可以很好的實作響應式的布局

。特别是當今這個時代,要面對的終端裝置隻會增加不會減少,那麼希望布局更容易的适配這些終端的布局,那麼CSS Grid Layout将會起到很大的作用,比如下面這個示例:

在你的浏覽器中打開上面這個Demo,改變你的浏覽器視窗的大小,你會看到布局的變化,這些變化都是用戶端自動在計算的,而且沒有依賴于任何媒體查詢。感興趣的同學,不仿親自試試。

CSS Grid 的出現,對于很多同學而言存在很多的困惑,比如前面提到的網格線的編号,甚至對于CSS Grid的了解也存在一定的誤區。@Jen Simmons整了九個視訊,針對CSS Grid 的九大誤區做過詳細的闡述:

  • 認為CSS Grid就是神,⽆無所不不能
  • 隻使⽤用百分⽐比設定尺⼨寸⼤大⼩小
  • Grid實作響應式布局依舊需要斷點
  • 被⽹網格線編寫搞糊塗
  • 總是使⽤用12列列⽹網格
  • 忽略略⾏行行的幂值
  • CSS Grid Layout != CSS Grid System (Framework) 8 等待IE11 的消亡,在開始使⽤用
  • 猶豫不不決

有關于這方面的詳細介紹,

你感興趣的話可以點選這裡直接擷取相關的視訊連結位址

随着CSS Grid的出現,社群就出現這樣的争論,Flexbox和Grid誰更好。在今年年初的時候,幾位大大在Twitter上就有相關的讨論:

@chriscoyier提了一個這樣的問題:

For y'all that have an understand of both CSS grid and flexbox, what's your favorite way of explaining the difference? (@chriscoyier January 25, 2019)

我摘取了 CSS Grid方面的專家(也稱得上是CSS Grid Layout的推動者或之父)分别是這樣回答的。先來看@rachelandrew的回答:

Flexbox is for one dimensional layout. A row OR a column. Grid is for two dimensional layout. Rows AND columns. (@rachelandrew January 25, 2019)

而 @jensimmons 是這樣回答的:

Grid makes actual columns and rows. Content will line up from one to the other, as you ask it to. Flexbox doesn’t. Not only in the second dimension (which is easiest to talk about), but also in the first dimension. Flexbox isn’t for most of the things we’ve been using it for. (@jensimmons January 25, 2019)

為了保持原汁原味,我沒有做任何的轉譯。當然,有關于這方面的讨論也可以閱讀 《

To Grid or to Flex?

随着Web布局的功能越來越強,我自認為未來的Web布局系統将會由Flexbox、Grid和Box Alignment幾大子產品組合在一起來建構。

剖析CSS-Tricks,為我所用

如果再細分一下,未來的Web布局系統所包括的主要知識點将會是:

其中CSS-Tricks的布局中就用到了Grid,Flexbox,書寫模式,對齊方式,媒體查詢,Transform和Scroll Snapping等。

有關于這幾個方面的詳細介紹,這裡就不做過多的闡述,如果感興趣的話,可以在小站上擷取相關的教程或查閱W3C上的功能子產品。

CSS混合模式 濾鏡

主要是用來處理圖檔的。這個有點類似于圖像編輯軟體一些功能:

剖析CSS-Tricks,為我所用

對于

img

picture

元素引入的圖像,可以使用

mix-blend-mode

filter

。如果是背景圖檔,可以使用

background-blend-mode

來處理。另外還有一個

isolation

屬性用來配合

mix-blend-mode

background-blend-mode

使用。

mix-blend-mode

background-blend-mode

不同的值得到的效果将會是不一樣的,比如:

剖析CSS-Tricks,為我所用

filter

對應屬性值的效果如下:

剖析CSS-Tricks,為我所用

如果把圖層混合模式和濾鏡結合起來一起使用,還可以創作出一些帶有藝術性的效果(以前類似的效果,隻能依賴于圖像處理軟體來完成):

剖析CSS-Tricks,為我所用

當然,他們不僅僅用于圖檔上,咱們還可以運用于任何的HTML元素上。

有關于 CSS圖層混合模式和濾鏡更多的教程可以點選這裡

CSS-Tricks網站運用的新特性除了上述之外,還有一些小特性,比如:

  • 漸變文本和邊框
  • CSS片段模闆
  • CSS計數器
  • clip-path

  • object-fit

  • 書寫模式

    writing-mode

  • 自定義元素

簡單地來過一下這些。

漸變文本

對于漸變文本的效果來說,可以說不是什麼新特性了,通過

background-clip: text

text-fill-color

的配合就可以輕易的實作,比如下面這個示例:

剖析CSS-Tricks,為我所用

上面截圖省略了背景圖檔的代碼,就上圖而言,使用多背景特性,引用了多張圖檔。

漸變邊框

針對于漸變邊框,主要是依賴于漸變屬性來和

background-clip

等屬性來完成。其實除了這種方式,不可以使用

border-image

一起來使用。就我個人而言我更推薦使用漸變屬性和背景相關屬性配合一起來做。比如下面這個效果:

剖析CSS-Tricks,為我所用

有關于這方面詳細的使用不在這做過多的闡述,如果你感興趣的話,可以閱讀早前寫的一篇博文《

聊聊雙11互動主動法中前端技術亮點

》。

除了漸變邊框,利用該方法你還可以實作一些更複雜的邊框效果,比如說紋理邊框。下面這個示例是

@Ana Tudor在Codepen寫的一個示例
剖析CSS-Tricks,為我所用

CSS 片段模闆

CSS片段子產品(

CSS Fragmentation Module Level 3

)中有一個

box-decoration-break

屬性。主要用來指定background、padding、border、border-image、box-shadow和clip在行内元素中如何使用。行内元素的盒模型是打斷的,也就是内聯盒子是多行的情況之下。比如下面這樣的一個效果:

剖析CSS-Tricks,為我所用

上面這個效果是 @Chokcoco 在他的博文《

有趣的

box-decoration-break

》中示範的一個效果。

box-decoration-break

主要有兩個值

slice

clone

。他們之間效果的差異,我用下圖來展示,大家一眼就能看出其中的差異性:

剖析CSS-Tricks,為我所用

該屬性對于内聯元素換行的場景寫一些效果是非常有效的。具體的介紹可以閱讀《

初探

box-decoration-break

CSS Tips:段落每行漸變色文本效果

CSS計數器其實涉及到三個屬性:

counter-increment

counter-reset

counter()

。一般情況都是配合CSS的僞元素

::before

::after

content

一起使用。可以用來計數(比如一個清單的序列号),

還可以來做一些小遊戲

。如果配合CSS自定義屬性,還可以實作動态修改生成的内容。比如下面這個示例:

剖析CSS-Tricks,為我所用

clip-path

clip-path

提供了一些函數功能,比如

polygon()

circle()

ellipse()

inset()

可以幫助我們繪制一些基本的形狀,如下圖所示:

剖析CSS-Tricks,為我所用

clip-path

可以實作一些不規則圖形的效果,比如你想你的使用者頭像的效果個性化一點,那麼就可以使用

polygon()

函數:

.avatar { 
    clip-path: polygon(0% 5%, 100% 0%, 100% 85%, 65% 80%, 75% 100%, 40% 80%, 0% 75%); 
}
           

來看

@Chris Coyier在Codepen上寫的一個案例
剖析CSS-Tricks,為我所用

clip-path

更多的介紹可以點選這裡

object-fit

object-fit

屬性

有點類似于

background-size

的功能,可以很好的幫助我們來處理

img

video

的适配效果。其還有另一個屬性是

object-position

,該屬性有點類似于

background-position

object-fit

一共有五個值,每個值所起的效果都不一樣,比如下圖所示的效果:

剖析CSS-Tricks,為我所用

writing-mode

簡單地來說是用來控制排版本的方式。比如下面這樣的一個豎排效果:

剖析CSS-Tricks,為我所用

事實上書寫模式涉及以的知識點非常的多,@hj_chen 老師有一篇博文《

Vertical typesetting with writing-mode revisited

》,做過詳細的闡述,如果你不喜歡閱讀英文,

可以點選這裡閱讀譯文

在新版本的CSS-Tricks中,還有一個自定義元素

circle-text

,用來制作圓形的文本排版。比如:

剖析CSS-Tricks,為我所用

有關于這部分,我并沒有深入學習,

如果你感興趣,可以點選這裡閱讀源碼

寫在最後

上面所說的隻是我自己閱讀CSS-Tricks網站源碼所獲得的知識點以及CSS一些優秀的特性。當然,很多同學可能會說,這裡所描述的特性,估計有很多浏覽器都不支援。事實上呢?也是如此,在不同的浏覽器中差異性是有所不同的。但這并不是阻礙我們去學習和探讨的原因所在。

就我個人而言,CSS雖然簡單,但其也并不容易。很多東西他就像是宇宙裡中未知的領域,我們需要不斷的去探索和挖掘:

剖析CSS-Tricks,為我所用
我們應該始終要有一顆好奇的心去探索,同時應該有顆勇敢的心去不斷的嘗試。隻有我們整個社群一起努力,才能推動其更進步,更上一層樓。

自從Web在1989年出現到今年(2019年),剛好有30年,借此機會,我要感謝Web,因為Web帶給我很多樂趣,也讓我認識很多朋友。

剖析CSS-Tricks,為我所用

繼續閱讀