8個硬核技巧帶你迅速提高CSS技術 | 掘金直播總結

做者:JowayYoung
倉庫:GithubCodePen
博客:官網掘金思否知乎
公衆號:IQ前端
特別聲明:原創不易,未經受權不得轉載或抄襲,如需轉載可聯繫筆者受權css

前言

前段時間筆者收到可愛美的小冊姐姐的邀請,作了人生首次直播分享。分享主題是《玩轉CSS的藝術之美》,跟筆者在9月底發佈的掘金小冊同名。html

9月底發佈的玩轉CSS的藝術之美,首日預售就達到709本,預售僅三日就破1000本。這也讓筆者感到驚訝,沒想到CSS技術仍是那麼受倔友們的歡迎,讓筆者以爲熬夜半年寫這本小冊仍是值得的,畢竟能將本身的學習心路分享出去,讓更多同窗學到更多東西,也是一件值得開心的事情。前端

因爲首次作直播分享,感受比較緊張,家裏網絡不是特別好,還有其餘緣由,致使認真準備的內容未在預料時間內完成分享,所以經過本文未來不及分享的內容整理出來。git

二期直播

目錄

對分享內容感興趣的同窗可關注筆者的公衆號IQ前端,回覆CSSPPT下載分享PPT。分享內容包含歷史背景概念原理開發技巧三節。第一二節比較無聊,可自行查看PPT,在此就很少說了。主要是第三節的乾貨,是筆者認真準備了好幾天的內容,每一個主題都會有對應的源碼及其效果。github

目錄

筆者選擇了一些經常使用甚至有些小冊都未說起到的乾貨做爲分享內容,相信這些內容能幫助同窗們在短時間內提高CSS編碼素質,實現一些看似只能由JS才能實現的效果。算法

  • 神奇的選擇器
  • 淺談佈局那些事
  • 繪製三角的原理
  • 完美極致的變量
  • 添油加醋的僞元素
  • 靈活多變的障眼法
  • 意向不到的內容插入
  • 無所不能的模擬點擊事件

準備工做segmentfault

整個分享過程不搞那些亂七八糟的環境搭建。既然只玩CSS,那只有html文件css文件就足夠了。另外還需一個瀏覽器Chrome和一個編輯器VSCode設計模式

VSCode還需安裝Live Sass CompilerLive Server兩個插件。Live Sass Compiler用於實時編譯sass/scss文件css文件Live Server用於啓動具備實時刷新功能的本地開發服務器,以處理靜態頁面和動態頁面。瀏覽器

新建index.htmlindex.scss。爲了使各大瀏覽器默認樣式一致,還需引入一個磨平瀏覽器默認樣式的css文件,同窗們可下載筆者寫好的reset.css到本地目錄裏。sass

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, minimum-scale=1, maximum-scale=1">
    <title>Hello CSS</title>
    <link rel="stylesheet" href="./reset.css">
    <link rel="stylesheet" href="./index.css">
</head>

<body class="flex-ct-x">
    <!-- ... -->
</body>

</html>
複製代碼
body {
    overflow: hidden;
    height: 100vh;
}
複製代碼

上述文件骨架完成後,打開index.scss,按F1Cmd + Shift + P打開命令面板,輸入Watch Sass監聽index.scss並生成index.css,再輸入Open With Live Server啓動本地開發服務器並打開瀏覽器。到此爲止就完成了全部準備工做了。

神奇的選擇器

不少CSS編碼習慣都是清一色的類而無相應的選擇器,層層嵌套的標籤都包含至少一個類。選擇器對比起來性能上確實沒後者那麼好,但現在瀏覽器對於CSS的解析速度已獲得大大的提高,徹底可忽略選擇器那丁點的性能問題。

但是CSS模塊衆多,依次推出的選擇器也不少。若無特別方法記熟這些選擇器對應的功能,也很難將選擇器發揮到最大做用。玩轉CSS的最關鍵一步是能熟悉大部分選擇器及其功能與使用場景

筆者根據選擇器的功能劃分出八大類,每一個類別的選擇器都能在一個使用場景中互相組合,記熟這些類別的選擇器,相信就能將選擇器發揮到最大做用。如下選擇器的經常使用選項裏若打勾可強行記熟,這些選擇器都是筆者久經沙場而標記出來且認爲是最好用的選擇器。

基礎選擇器

選擇器 別名 說明 版本 經常使用
tag 標籤選擇器 指定類型的標籤 1
#id ID選擇器 指定身份的標籤 1
.class 類選擇器 指定類名的標籤 1
* 通配選擇器 全部類型的標籤 2

層次選擇器

選擇器 別名 說明 版本 經常使用
elemP elemC 後代選擇器 元素的後代元素 1
elemP>elemC 子代選擇器 元素的子代元素 2
elem1+elem2 相鄰同胞選擇器 元素相鄰的同胞元素 2
elem1~elem2 通用同胞選擇器 元素後面的同胞元素 3

集合選擇器

選擇器 別名 說明 版本 經常使用
elem1,elem2 並集選擇器 多個指定的元素 1
elem.class 交集選擇器 指定類名的元素 1

條件選擇器

選擇器 說明 版本 經常使用
:lang 指定標記語言的元素 2 ×
:dir() 指定編寫方向的元素 4 ×
:has 包含指定元素的元素 4 ×
:is 指定條件的元素 4 ×
:not 非指定條件的元素 4
:where 指定條件的元素 4 ×
:scope 指定元素做爲參考點 4 ×
:any-link 全部包含href連接元素 4 ×
:local-link 全部包含href且屬於絕對地址的連接元素 4 ×

狀態選擇器

選擇器 說明 版本 經常使用
:active 鼠標激活的元素 1 ×
:hover 鼠標懸浮的元素 1
:link 未訪問的連接元素 1 ×
:visited 已訪問的連接元素 1 ×
:target 當前錨點的元素 3 ×
:focus 輸入聚焦的表單元素 2
:required 輸入必填的表單元素 3
:valid 輸入合法的表單元素 3
:invalid 輸入非法的表單元素 3
:in-range 輸入範圍之內的表單元素 3 ×
:out-of-range 輸入範圍之外的表單元素 3 ×
:checked 選項選中的表單元素 3
:optional 選項可選的表單元素 3 ×
:enabled 事件啓用的表單元素 3 ×
:disabled 事件禁用的表單元素 3
:read-only 只讀的表單元素 3 ×
:read-write 可讀可寫的表單元素 3 ×
:target-within 內部錨點元素處於激活狀態的元素 4 ×
:focus-within 內部表單元素處於聚焦狀態的元素 4
:focus-visible 輸入聚焦的表單元素 4 ×
:blank 輸入爲空的表單元素 4 ×
:user-invalid 輸入合法的表單元素 4 ×
:indeterminate 選項未定的表單元素 4 ×
:placeholder-shown 佔位顯示的表單元素 4
:current() 瀏覽中的元素 4 ×
:past() 已瀏覽的元素 4 ×
:future() 未瀏覽的元素 4 ×
:playing 開始播放的媒體元素 4 ×
:paused 暫停播放的媒體元素 4 ×

結構選擇器

選擇器 說明 版本 經常使用
:root 文檔的根元素 3 ×
:empty 無子元素的元素 3
:nth-child(n) 元素中指定順序索引的元素 3
:nth-last-child(n) 元素中指定逆序索引的元素 3 ×
:first-child 元素中爲首的元素 2
:last-child 元素中爲尾的元素 3
:only-child 父元素僅有該元素的元素 3
:nth-of-type(n) 標籤中指定順序索引的標籤 3
:nth-last-of-type(n) 標籤中指定逆序索引的標籤 3 ×
:first-of-type 標籤中爲首的標籤 3
:last-of-type 標籤中爲尾標籤 3
:only-of-type 父元素僅有該標籤的標籤 3

屬性選擇器

選擇器 說明 版本 經常使用
[attr] 指定屬性的元素 2
[attr=val] 屬性等於指定值的元素 2
[attr*=val] 屬性包含指定值的元素 3
[attr^=val] 屬性以指定值開頭的元素 3
[attr$=val] 屬性以指定值結尾的元素 3
[attr~=val] 屬性包含指定值(完整單詞)的元素(不推薦使用) 2 ×
[attr|=val] 屬性以指定值(完整單詞)開頭的元素(不推薦使用) 2 ×

僞元素

選擇器 說明 版本 經常使用
::before 在元素前插入的內容 2
::after 在元素後插入的內容 2
::first-letter 元素的首字母 1 ×
::first-line 元素的首行 1 ×
::selection 鼠標選中的元素 3 ×
::backdrop 全屏模式的元素 4 ×
::placeholder 表單元素的佔位 4

選擇器真正的用處不只僅是說明選項裏的描述,更可能是搭配起來能起到的最大做用。這些選擇器組成的選擇器系統是整個CSS體系裏的核心,使用選擇器能帶來如下好處。

  • 清晰易讀:對於那些結構與行爲分離的寫法,使用sass/less編寫屬性時結構會更清晰易讀,減小不少無用或少用的類,保持css文件的整潔性和觀賞性
  • 確保一致:減小修改類而有可能致使樣式失效的問題,有時修改類但未確保HTML和CSS的一致而致使樣式失效
  • 剔除累贅:減小無實質性使用的類,例如不少層嵌套的標籤,這些標籤可能只使用到一個屬性,就不必新建類關聯
  • 高效流暢:使用選擇器可實現一些看似只能由JS才能實現的效果,既減小代碼量也減小JS對DOM的操做,使得交互效果更流暢

淺談佈局那些事

掌握一些經常使用佈局是一個前端必不可少的技能。養成看設計圖就能大概規劃出總體佈局的前提是必須熟悉這些經常使用佈局的特色與構造。曾經需結合不少屬性才能完成一個佈局,現在在現代屬性的加持下能更好地快速實現各類佈局,節約更多時間去作更重要的事情。

全屏佈局

經典的全屏佈局頂部底部主體三部分組成,其特色爲三部分左右滿屏拉伸頂部底部高度固定主體高度自適應。該佈局很常見,也是大部分Web應用主體的主流佈局。一般使用<header><footer><main>三個標籤語義化排版,<main>內還可插入<aside>側欄或其餘語義化標籤。

全屏佈局

<div class="fullscreen-layout">
    <header></header>
    <main></main>
    <footer></footer>
</div>
複製代碼

position + left/right/top/bottom

三部分統一聲明left:0right:0將其左右滿屏拉伸;頂部和底部分別聲明top:0bottom:0將其吸頂和吸底,並聲明倆高度爲固定值;將主體的topbottom分別聲明爲頂部高度和底部高度。經過絕對定位的方式將三部分固定在特定位置,使其互不影響。

.fullscreen-layout {
    position: relative;
    width: 400px;
    height: 400px;
    header,
    footer,
    main {
        position: absolute;
        left: 0;
        right: 0;
    }
    header {
        top: 0;
        height: 50px;
        background-color: #f66;
    }
    footer {
        bottom: 0;
        height: 50px;
        background-color: #66f;
    }
    main {
        top: 50px;
        bottom: 50px;
        background-color: #3c9;
    }
}
複製代碼

flex

使用flex實現會更簡潔。display:flex默認會令子節點橫向排列,需聲明flex-direction:column改變子節點排列方向爲縱向排列;頂部和底部高度固定,因此主體需聲明flex:1讓高度自適應。

.fullscreen-layout {
    display: flex;
    flex-direction: column;
    width: 400px;
    height: 400px;
    header {
        height: 50px;
        background-color: #f66;
    }
    footer {
        height: 50px;
        background-color: #66f;
    }
    main {
        flex: 1;
        background-color: #3c9;
    }
}
複製代碼

<main>需表現成可滾動狀態,千萬不要聲明overflow:auto讓容器自適應滾動,這樣作有可能由於其餘格式化上下文的影響而致使自適應滾動失效或產生其餘未知效果。需在<main>內插入一個<div>並聲明以下。

div {
    overflow: hidden;
    height: 100%;
}
複製代碼
多列布局
兩列布局

經典的兩列布局左右兩列組成,其特色爲一列寬度固定另外一列寬度自適應兩列高度固定且相等。如下以左列寬度固定和右列寬度自適應爲例,反之同理。

多列布局-兩列布局

<div class="two-column-layout">
    <div class="left"></div>
    <div class="right"></div>
</div>
複製代碼

float + margin-left/right

左列聲明float:left和固定寬度,因爲float使節點脫流,右列需聲明margin-left爲左列寬度,以保證兩列不會重疊。

.two-column-layout {
    width: 400px;
    height: 400px;
    .left {
        float: left;
        width: 100px;
        height: 100%;
        background-color: #f66;
    }
    .right {
        margin-left: 100px;
        height: 100%;
        background-color: #66f;
    }
}
複製代碼

overflow + float

左列聲明同上,右列聲明overflow:hidden使其造成BFC區域與外界隔離。BFC相關詳情請查看小冊第4章盒模型

.two-column-layout {
    width: 400px;
    height: 400px;
    .left {
        float: left;
        width: 100px;
        height: 100%;
        background-color: #f66;
    }
    .right {
        overflow: hidden;
        height: 100%;
        background-color: #66f;
    }
}
複製代碼

flex

使用flex實現會更簡潔。左列聲明固定寬度,右列聲明flex:1自適應寬度。

.two-column-layout {
    display: flex;
    width: 400px;
    height: 400px;
    .left {
        width: 100px;
        background-color: #f66;
    }
    .right {
        flex: 1;
        background-color: #66f;
    }
}
複製代碼
三列布局

經典的三列布局左中右三列組成,其特色爲連續兩列寬度固定剩餘一列寬度自適應三列高度固定且相等。如下以左中列寬度固定和右列寬度自適應爲例,反之同理。總體的實現原理與上述兩列布局一致。

多列布局-三列布局

<div class="three-column-layout">
    <div class="left"></div>
    <div class="center"></div>
    <div class="right"></div>
</div>
複製代碼

爲了讓右列寬度自適應計算,就不使用float + margin-left的方式了,若使用margin-left還得結合左中列寬度計算。

overflow + float

.three-column-layout {
    width: 400px;
    height: 400px;
    .left {
        float: left;
        width: 50px;
        height: 100%;
        background-color: #f66;
    }
    .center {
        float: left;
        width: 100px;
        height: 100%;
        background-color: #66f;
    }
    .right {
        overflow: hidden;
        height: 100%;
        background-color: #3c9;
    }
}
複製代碼

flex

.three-column-layout {
    display: flex;
    width: 400px;
    height: 400px;
    .left {
        width: 50px;
        background-color: #f66;
    }
    .center {
        width: 100px;
        background-color: #66f;
    }
    .right {
        flex: 1;
        background-color: #3c9;
    }
}
複製代碼
聖盃佈局與雙飛翼佈局

經典的聖盃佈局雙飛翼佈局都是由左中右三列組成,其特色爲左右兩列寬度固定中間一列寬度自適應三列高度固定且相等。其實也是上述兩列布局和三列布局的變體,總體的實現原理與上述N列布局一致,可能就是一些細節需注意。

聖盃佈局雙飛翼佈局在大致相同下也存在一點不一樣,區別在於雙飛翼佈局中間列需插入一個子節點。在常規的實現方式中也是在這個中間列裏作文章,如何使中間列內容不被左右列遮擋

  • 相同
    • 中間列放首位且聲明其寬高佔滿父節點
    • 被擠出的左右列使用floatmargin負值將其拉回與中間列處在同一水平線上
  • 不一樣
    • 聖盃佈局:父節點聲明padding爲左右列留出空位,將左右列固定在空位上
    • 雙飛翼佈局:中間列插入子節點並聲明margin爲左右列讓出空位,將左右列固定在空位上

多列布局-聖盃佈局

聖盃佈局float + margin-left/right + padding-left/right

因爲浮動節點在位置上不能高於前面或平級的非浮動節點,不然會致使浮動節點下沉。所以在編寫HTML結構時,將中間列節點挪到右列節點後面。

<div class="grail-layout-x">
    <div class="left"></div>
    <div class="right"></div>
    <div class="center"></div>
</div>
複製代碼
.grail-layout-x {
    padding: 0 100px;
    width: 400px;
    height: 400px;
    .left {
        float: left;
        margin-left: -100px;
        width: 100px;
        height: 100%;
        background-color: #f66;
    }
    .right {
        float: right;
        margin-right: -100px;
        width: 100px;
        height: 100%;
        background-color: #66f;
    }
    .center {
        height: 100%;
        background-color: #3c9;
    }
}
複製代碼

雙飛翼佈局float + margin-left/right

HTML結構大致同上,只是在中間列裏插入一個子節點<div>。根據二者區別,CSS聲明會與上述聖盃佈局有一點點出入,可觀察對比找出不一樣地方。

<div class="grail-layout-y">
    <div class="left"></div>
    <div class="right"></div>
    <div class="center">
        <div></div>
    </div>
</div>
複製代碼
.grail-layout-y {
    width: 400px;
    height: 400px;
    .left {
        float: left;
        width: 100px;
        height: 100%;
        background-color: #f66;
    }
    .right {
        float: right;
        width: 100px;
        height: 100%;
        background-color: #66f;
    }
    .center {
        margin: 0 100px;
        height: 100%;
        background-color: #3c9;
    }
}
複製代碼

聖盃佈局/雙飛翼佈局flex

使用flex實現聖盃佈局/雙飛翼佈局可忽略上述分析,左右兩列寬度固定,中間列寬度自適應。

<div class="grail-layout">
    <div class="left"></div>
    <div class="center"></div>
    <div class="right"></div>
</div>
複製代碼
.grail-layout {
    display: flex;
    width: 400px;
    height: 400px;
    .left {
        width: 100px;
        background-color: #f66;
    }
    .center {
        flex: 1;
        background-color: #3c9;
    }
    .right {
        width: 100px;
        background-color: #66f;
    }
}
複製代碼
均分佈局

經典的均分佈局多列組成,其特色爲每列寬度相等每列高度固定且相等。整體來講也是最簡單的經典佈局,因爲每列寬度相等,因此很易找到合適的方式處理。

多列布局-均分佈局

<div class="average-layout">
    <div class="one"></div>
    <div class="two"></div>
    <div class="three"></div>
    <div class="four"></div>
</div>
複製代碼
.one {
    background-color: #f66;
}
.two {
    background-color: #66f;
}
.three {
    background-color: #f90;
}
.four {
    background-color: #09f;
}
複製代碼

float + width

每列寬度聲明爲相等的百分比,如有4列則聲明width:25%。N列就用公式100 / n求出最終百分比寬度,記得保留2位小數,懶人還可用width:calc(100% / n)自動計算呢。

.average-layout {
    width: 400px;
    height: 400px;
    div {
        float: left;
        width: 25%;
        height: 100%;
    }
}
複製代碼

flex

使用flex實現會更簡潔。節點聲明display:flex後,生成的FFC容器裏全部子節點的高度都相等,由於容器的align-items默認爲stretch,全部子節點將佔滿整個容器的高度。每列聲明flex:1自適應寬度。

.average-layout {
    display: flex;
    width: 400px;
    height: 400px;
    div {
        flex: 1;
    }
}
複製代碼
居中佈局

居中佈局父容器若干個子容器組成,子容器在父容器中橫向排列或豎向排列且呈水平居中或垂直居中。居中佈局是一個很經典的問題,因此筆者在小冊中羅列了全部居中佈局方式,詳情請查看小冊第6章佈局方式

居中佈局

在此直接上一個目前最簡單最高效的居中方式。display:flexmargin:auto的強行組合,同窗們自行體會。

<div class="center-layout">
    <div></div>
</div>
複製代碼
.center-layout {
    display: flex;
    width: 400px;
    height: 400px;
    background-color: #f66;
    div {
        margin: auto;
        width: 100px;
        height: 100px;
        background-color: #66f;
    }
}
複製代碼

繪製三角的原理

盒模型從理論上來講是一個標準的矩形,很難將其聯想到基於盒模型繪製一個三角形。固然存在一個叫clip-path的屬性,可繪製三角形,鑑於其兼容性較差一般不會大範圍使用它繪製三角形。

不少同窗都會基於盒模型編寫三角形,但大部分都是複製粘貼的操做。從原理上正確理解其成因,才能無需複製粘貼就能駕輕就熟地繪製各類三角形。如下從零到一熟悉一次繪製三角形的原理。

繪製一個邊框分別爲四種顏色的正方形。

三角原理-1

<div class="triangle"></div>
複製代碼
.triangle {
    border: 50px solid;
    border-left-color: #f66;
    border-right-color: #66f;
    border-top-color: #f90;
    border-bottom-color: #09f;
    width: 200px;
    height: 200px;
}
複製代碼

分別將widthheight累減到0,發現正方形由四個不一樣顏色的等腰三角形組成。

三角原理-2

.triangle {
    border: 50px solid;
    border-left-color: #f66;
    border-right-color: #66f;
    border-top-color: #f90;
    border-bottom-color: #09f;
    width: 0;
    height: 0;
}
複製代碼

嘗試將右邊框顏色聲明爲透明,會發現右邊框隱藏起來。

三角原理-3

.triangle {
    border: 50px solid;
    border-left-color: #f66;
    border-right-color: transparent;
    border-top-color: #f90;
    border-bottom-color: #09f;
    width: 0;
    height: 0;
}
複製代碼

一樣原理,將上邊框顏色和下邊框顏色同時聲明爲透明,就會獲得一個指向右邊的三角形。

三角原理-4

.triangle {
    border: 50px solid;
    border-left-color: #f66;
    border-right-color: transparent;
    border-top-color: transparent;
    border-bottom-color: transparent;
    width: 0;
    height: 0;
}
複製代碼

可簡寫成如下代碼。細心的同窗可能還會發現三角形的寬是高的2倍,而高正好是邊框寬度border-width。從中可得出一個技巧:若繪製三角形的方向爲左右上下,則將四條邊框顏色聲明爲透明且將指定方向的反方向的邊框着色,便可獲得所需方向的三角形

.triangle {
    border: 50px solid transparent;
    border-left-color: #f66;
    width: 0;
    height: 0;
}
複製代碼

若繪製左上角、左下角、右上角或右下角的三角形,使用上述技巧就沒法完成了。可稍微變通思惟,其實指向左上角的三角形是由左邊框和上邊框組成,其餘三角形也是如此。

三角原理-5

.triangle {
    border: 50px solid transparent;
    border-left-color: #f66;
    border-top-color: #f66;
    width: 0;
    height: 0;
}
複製代碼

基於上述原理,可駕輕就熟繪製出左右上下、左上角、左下角、右上角和右下角的三角形了,再結合絕對定位(position/left/right/top/bottom)、邊距(margin/margin-*)或變換(transform)調整位置便可。

三角原理-6

.triangle {
    border: 50px solid transparent;
    width: 0;
    height: 0;
    &.left {
        border-right-color: #f66;
    }
    &.right {
        border-left-color: #f66;
    }
    &.top {
        border-bottom-color: #f66;
    }
    &.bottom {
        border-top-color: #f66;
    }
    &.left-top {
        border-left-color: #f66;
        border-top-color: #f66;
    }
    &.left-bottom {
        border-left-color: #f66;
        border-bottom-color: #f66;
    }
    &.right-top {
        border-right-color: #f66;
        border-top-color: #f66;
    }
    &.right-bottom {
        border-right-color: #f66;
        border-bottom-color: #f66;
    }
}
複製代碼

完美極致的變量

變量又名自定義屬性,指可在整個文檔中重複使用的值。它由自定義屬性--var和函數var()組成,var()用於引用自定義屬性。使用變量能帶來如下好處。

  • 減小樣式代碼的重複性
  • 增長樣式代碼的擴展性
  • 提升樣式代碼的靈活性
  • 增多一種CSS與JS的通信方式
  • 不用深層遍歷DOM改變某個樣式

同時變量也是瀏覽器原生特性,無需通過任何轉譯可直接運行,也是DOM對象,極大便利了CSS與JS間的聯繫。變量除了具有簡潔性和複用性,在重構組件樣式時能讓代碼更易控制,同時還隱藏了一個強大的技巧,那就是與calc()結合使用。

看看一個簡單的例子。一個條形加載條一般由幾條線條組成,每條線條對應一個存在不一樣時延的相同動畫,經過時間差運行相同動畫,從而產生加載效果。估計大部分同窗可能會把代碼編寫成如下形式。

條形加載條

<ul class="strip-loading">
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ul>
複製代碼
.strip-loading {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 200px;
    height: 200px;
    li {
        border-radius: 3px;
        width: 6px;
        height: 30px;
        background-color: #f66;
        animation: beat 1s ease-in-out infinite;
        & + li {
            margin-left: 5px;
        }
        &:nth-child(2) {
            animation-delay: 200ms;
        }
        &:nth-child(3) {
            animation-delay: 400ms;
        }
        &:nth-child(4) {
            animation-delay: 600ms;
        }
        &:nth-child(5) {
            animation-delay: 800ms;
        }
        &:nth-child(6) {
            animation-delay: 1s;
        }
    }
}
@keyframes beat {
    0%,
    100% {
        transform: scaleY(1);
    }
    50% {
        transform: scaleY(.5);
    }
}
複製代碼

分析代碼發現,每一個<li>只是animation-delay不一樣,其他代碼則徹底相同,換成其餘相似的List集合,那豈不是有10個<li>就寫10個:nth-child(n)。顯然這種方式不靈活也不易封裝成組件,若能像JS那樣封裝成一個函數,並根據參數輸出不一樣樣式效果,那就更棒了。

對於HTML部分的修改,讓每一個<li>擁有一個本身做用域下的變量。對於CSS部分的修改,就需分析哪些屬性是隨着index遞增而發生規律變化的,對規律變化的部分使用變量表達式代替便可。固然如下<li style="--line-index: n;"></li>可用React JSXVue Template的遍歷語法編寫。

<ul class="strip-loading">
    <li style="--line-index: 1;"></li>
    <li style="--line-index: 2;"></li>
    <li style="--line-index: 3;"></li>
    <li style="--line-index: 4;"></li>
    <li style="--line-index: 5;"></li>
    <li style="--line-index: 6;"></li>
</ul>
複製代碼
.strip-loading {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 200px;
    height: 200px;
    li {
        --time: calc((var(--line-index) - 1) * 200ms);
        border-radius: 3px;
        width: 6px;
        height: 30px;
        background-color: #f66;
        animation: beat 1.5s ease-in-out var(--time) infinite;
        & + li {
            margin-left: 5px;
        }
    }
}
@keyframes beat {
    0%,
    100% {
        transform: scaleY(1);
    }
    50% {
        transform: scaleY(.5);
    }
}
複製代碼

代碼中的變量--line-index--time使每一個<li>擁有一個屬於本身的做用域。例如第二個<li>--line-index的值爲2,--time的計算值爲200ms,換成第三個<li>後這兩個值又會不一樣了。這就是變量的做用範圍所致(在當前節點塊做用域及其子節點塊做用域下有效)。

calc(var(--line-index) * 200ms)就像一個JS函數,在當前節點的做用域上讀取相應的變量,從而計算出具體數值並交由瀏覽器初始化。從中可得出一個技巧:List集合裏具有與索引遞增相關的屬性值均可用變量與calc()結合使用生成出來

還記得小學時代學習圓周率的場景嗎,曾經有學者將一個圓形劃分爲不少很小的矩形,若這些矩形劃分得足夠細,那麼也可拼在一塊兒變成一個圓形。

將圓形劃分爲360個小矩形且每一個矩形相對於父容器絕對定位,聲明transform-origincenter bottom將小矩形的變換基準變動爲最底部最中間,每一個小矩形按照遞增角度順時針旋轉N度,就會造成一個圓形。此時按照遞增角度調整小矩形的背景色相,就會看到意想不到的漸變效果了。

  • 每一個小矩形的遞增角度:--Θ:calc(var(--line-index) / var(--line-count) * 1turn)
  • 每一個小矩形的背景色相:filter:hue-rotate(var(--Θ))
  • 每一個小矩形的旋轉角度:transform:rotate(var(--Θ))

若將小矩形的尺寸和數量設置更細更多,總體的漸變效果就會更均勻。

漸變圓形

<ul class="gradient-circular" style="--line-count: 360;">
    <li style="--line-index: 1;"></li>
    ...
    <li style="--line-index: 360;"></li>
    <!-- 360個<li>,可用模板語法生成 -->
</ul>
複製代碼
.gradient-circular {
    position: relative;
    width: 4px;
    height: 200px;
    li {
        --Θ: calc(var(--line-index) / var(--line-count) * 1turn);
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        background-color: #3c9;
        filter: hue-rotate(var(--Θ));
        transform-origin: center bottom;
        transform: rotate(var(--Θ));
    }
}
複製代碼

添油加醋的僞元素

有時爲了實現某個效果而往頁面裏反覆添加標籤變得很繁瑣,添加太多標籤反而很差處理而變得難以維護。此時會引入僞元素這個概念解決上述問題。正是僞元素能解決一些可不添加其餘標籤而起到佔位做用,筆者才稱僞元素「添油加醋」

上述選擇器分類有說起僞元素,狹義上來講選擇器除了僞元素,其餘都是僞類僞元素僞類雖然都是選擇器,但它們仍是存在一絲絲的差異。

  • 僞元素一般是一些實體選擇器,選擇知足指定條件的DOM,例如::selection::first-letter::first-line
  • 僞類一般是一些狀態選擇器,選擇處於特定狀態的DOM,例如:hover:focus:checked

僞元素指頁面裏不存在的元素。僞元素在HTML代碼裏未聲明卻能正常顯示,在頁面渲染時看到這些原本不存在的元素髮揮着重要做用。:before:after是兩個很重要的僞元素,早在CSS2就出現了。

起初僞元素的前綴使用單冒號語法。隨着CSS改革,僞元素的前綴被修改爲雙冒號語法:before/:after今後變成::before/::after,用來區分僞類,未說起的僞元素同理。若兼容低版本瀏覽器,還需使用:before:after

二者最主要的區別就是僞類使用單冒號語法僞元素使用雙冒號語法。固然筆者仍是提倡同窗們使用單冒號語法標記僞類,使用雙冒號語法標記僞元素,這樣在代碼形式上就能一眼區分出來。

::before::after的使用場景不少,也是筆者着重研究的技巧之一。::before/::after必須結合content使用,一般用做修飾節點,爲節點插入一些多餘的東西,但又不想內嵌一些其餘標籤。若插入2個如下(包含2個)的修飾,建議使用::before/::after

說時遲那時快,立馬結合上述繪製三角形的原理繪製一個經常使用的氣泡對話框,圓滾滾的身子帶上一個三角形的尾巴。氣泡對話框的身板就是一個圓角矩形,可用<div>直接繪製,小尾巴是一個三角形,可用::after佔位並繪製。這樣就無需在<div>裏添加一個<i>繪製小尾巴了。

氣泡對話框

<div class="bubble-box">iCSS</div>
複製代碼
.bubble-box {
    position: relative;
    border-radius: 5px;
    width: 200px;
    height: 50px;
    background-color: #f90;
    line-height: 50px;
    text-align: center;
    font-size: 20px;
    color: #fff;
    &::after {
        position: absolute;
        left: 100%;
        top: 50%;
        margin-top: -5px;
        border: 5px solid transparent;
        border-left-color: #f90;
        content: "";
    }
}
複製代碼

從中可得出一個技巧:若爲節點作一些修飾卻不想插入其餘標籤,可用::before和::after代替,但適用於2個佔位如下。其實這個也不算什麼特別技巧,只是不少同窗都不會去注意這種用法,有需求都是直接添加標籤。也許如下說起的障眼法內容插入會讓同窗們對僞元素刮目相看。

靈活多變的障眼法

上述使用::after簡單地繪製氣泡對話框的尾巴,然而複雜一點的帶邊框氣泡對話框可否也使用僞元素繪製呢。看到這裏先不要往下看代碼,自行思考1分鐘想一想實現方法。

帶邊框氣泡對話框

答案固然是可行的。如下是整個帶邊框氣泡對話框的拆解,總體由三部分組成:帶邊框圓角矩形、黑色三角形、橙色三角形。先將兩個三角形錯位疊加生成一個箭頭狀的圖形,再將該圖形疊加到帶邊框圓角矩形的右邊,最後將黑色三角形着色成白色,就能獲得上圖的帶邊框氣泡對話框了。

帶邊框氣泡對話框-原理

<div class="bubble-empty-box">iCSS</div>
複製代碼
.bubble-empty-box {
    position: relative;
    border: 2px solid #f90;
    border-radius: 5px;
    width: 200px;
    height: 50px;
    line-height: 46px;
    text-align: center;
    font-size: 20px;
    color: #f90;
    &::before {
        position: absolute;
        left: 100%;
        top: 50%;
        margin: -5px 0 0 2px;
        border: 5px solid transparent;
        border-left-color: #f90;
        content: "";
    }
    &::after {
        position: absolute;
        left: 100%;
        top: 50%;
        margin-top: -4px;
        border: 4px solid transparent;
        border-left-color: #fff;
        content: "";
    }
}
複製代碼

總體實現思路就是一種障眼法,正確來講就是將圖形錯位疊加產生另外一種效果,在平面設計中叫作佔位疊加。有了這種設計思想,其實能使用CSS創造出不少意向不到的障眼法效果。

當你碰見心儀妹紙時,內心噗通噗通地跳動,此時此刻可用純CSS描繪你的心情。使用單個<div>結合::before::after,經過錯位疊加的方式生成一個心形。在疊加前看看如下圖形,是否是發現很像米老鼠呢。

動感心形-原理1

  • 聲明<div>形狀爲正方形並以中心順時針旋轉45deg
  • 聲明::before::after繼承<div>尺寸並分別絕對定位到左上角和右上角
  • 聲明::before::after的圓角率爲100%

動感心形

<div class="heart-shape"></div>
複製代碼
.heart-shape {
    position: relative;
    width: 200px;
    height: 200px;
    background-color: #f66;
    transform: rotate(45deg);
    &::before,
    &::after {
        position: absolute;
        left: 0;
        top: 0;
        border-radius: 100%;
        width: 100%;
        height: 100%;
        background-color: #f66;
        content: "";
    }
    &::before {
        transform: translateX(-50%);
    }
    &::after {
        transform: translateY(-50%);
    }
}
複製代碼

最後巧妙利用transform::before::after平移到相應位置產生疊加錯覺。這時分別對::before::after着色,看看其中的奧祕。

動感心形-原理2

在這個基礎上來一個更高級的玩法,添加漸變效果讓心形變得更麼麼噠。

  • 聲明<div>從上到下(實際效果是從右上角到左下角)漸變着色
  • 因爲::before從旋轉後的<div>X軸往左平移過去,因此其着色效果與<div>一致
  • 因爲::after從旋轉後的<div>Y軸往上平移過去,因此其中線位置漸變着色必須與<div>頂部漸變着色的顏色一致(具體往下分析)

總體漸變效果的重點在::after上,因爲::after下半部疊加在<div>上,因此下半部顏色必須透明,上半部底部(中線位置)漸變着色必須與<div>頂部漸變着色的顏色一致,這樣才能作到無縫銜接。經過Windows系統MacOS系統的測試,在Windows系統下的透明漸變位置需在51%的地方開始,這與屏幕設備的分辨率和廣色域有關。

最後爲了讓漸變心形看起來更具立體感,給它繪製個陰影吧。若以爲這個漸變更感心形很美,可隨手轉發給女朋友哇!

漸變更感心形

<div class="gradient-heart-shape"></div>
複製代碼
.gradient-heart-shape {
    position: relative;
    width: 200px;
    height: 200px;
    background-image: linear-gradient(to bottom, #09f, #f66);
    box-shadow: 0 0 20px rgba(#000, .8);
    transform: rotate(45deg);
    &::before,
    &::after {
        position: absolute;
        left: 0;
        top: 0;
        border-radius: 100%;
        width: 100%;
        height: 100%;
        content: "";
    }
    &::before {
        background-image: linear-gradient(to bottom, #09f, #f66);
        transform: translateX(-50%);
    }
    &::after {
        background-image: linear-gradient(to bottom, #3c9, #09f 50%, transparent 50%, transparent);
        transform: translateY(-50%);
    }
}
複製代碼

意向不到的內容插入

上述提到::before/::after必須結合content使用,那麼content就真的只能插入普通字符串嗎?content何止這麼簡單,如下推廣幾種少見但強大的內容插入技巧。經過這幾種技巧,就能很方便地將讀取到的數據動態插入到::before::after中。

  • 內容拼接
  • 結合attr()使用
  • 結合變量計數器使用

內容拼接

常規操做是content:"CSS",也可拼接多個字符串,有些同窗可能第一時間想起content:"Hello "+"CSS"。拜託,這不是JS而是CSS,CSS字符串拼接固然有本身的規則。CSS字符串拼接既不能使用+相連也可不用空格間隔。

.elem {
    content: "Hello ""CSS"; // 等價於"Hello " "CSS"
    content: "Hello" attr(data-name); // 與attr()拼接
    content: counter(progress) "%"; // 與counter()拼接
}
複製代碼

結合attr()使用

attr()是一個被忽略的選擇器,它有着強大的屬性捕獲功能。有這麼一個場景,一個數據集合需遍歷到每一個DOM上並把某個字段插入到其::after上。這該怎麼辦,好像95%的同窗都不會使用JS獲取節點的::before::after。這時attr()就派上用場了。

<li v-for="v in list" :key="v.id" :data-name="v.name">
複製代碼
li::after {
    content: attr(data-name);
}
複製代碼

一行CSS代碼搞掂,還用什麼JS去獲取節點的::after呢。固然contentattr()的使用場景不止那一點。

:hover做用於鼠標懸浮的節點,是一個很好用的選擇器。在特定場景可代替mouseentermouseleave兩個鼠標事件,加上transtion讓節點的動畫更絲滑。結合attr()有一個很好用的場景,就是鼠標懸浮在某個節點上顯示提示浮層,提示浮層裏包含着該動做的文本。

  • 給節點標記一個用戶屬性data-*
  • 當鼠標懸浮在該節點上觸發:hover
  • 經過attr()獲取data-*的內容
  • data-*的內容賦值到僞元素content

懸浮提示

<ul class="hover-tips">
    <li data-name="姨媽紅"></li>
    <li data-name="基佬紫"></li>
    <li data-name="籮底橙"></li>
    <li data-name="姣婆藍"></li>
    <li data-name="大糞青"></li>
    <li data-name="原諒綠"></li>
</ul>
複製代碼
$color-list: #f66 #66f #f90 #09f #9c3 #3c9;
.hover-tips {
    display: flex;
    justify-content: space-between;
    width: 200px;
    li {
        position: relative;
        padding: 2px;
        border: 2px solid transparent;
        border-radius: 100%;
        width: 24px;
        height: 24px;
        background-clip: content-box;
        cursor: pointer;
        transition: all 300ms;
        &::before,
        &::after {
            position: absolute;
            left: 50%;
            bottom: 100%;
            opacity: 0;
            transform: translate3d(0, -30px, 0);
            transition: all 300ms;
        }
        &::before {
            margin: 0 0 12px -35px;
            border-radius: 5px;
            width: 70px;
            height: 30px;
            background-color: rgba(#000, .5);
            line-height: 30px;
            text-align: center;
            color: #fff;
            content: attr(data-name);
        }
        &::after {
            margin-left: -6px;
            border: 6px solid transparent;
            border-top-color: rgba(#000, .5);
            width: 0;
            height: 0;
            content: "";
        }
        @each $color in $color-list {
            $index: index($color-list, $color);
            &:nth-child(#{$index}) {
                background-color: $color;
                &:hover {
                    border-color: $color;
                }
            }
        }
        &:hover {
            &::before,
            &::after {
                opacity: 1;
                transform: translate3d(0, 0, 0);
            }
        }
    }
}
複製代碼

結合變量計數器使用

如今來玩高級一點的東西,先不作任何鋪墊,接着往下看便可,反正就是content結合變量計數器的使用場景。

筆者想作一個實時顯示進度的懸浮球,跟着筆者一塊兒敲代碼吧。先畫一個綠油油的波波。

狀態懸浮球-原理1

<div class="state-ball">
    <div class="wave"></div>
</div>
複製代碼
.state-ball {
    overflow: hidden;
    position: relative;
    padding: 5px;
    border: 3px solid #3c9;
    border-radius: 100%;
    width: 150px;
    height: 150px;
    background-color: #fff;
    .wave {
        position: relative;
        border-radius: 100%;
        width: 100%;
        height: 100%;
        background-image: linear-gradient(to bottom, #af8 13%, #3c9 91%);
    }
}
複製代碼

進度一般都是從底部往頂部逐漸提高,可用::before繪製一個圓形遮罩層,進度變化時將遮罩層一直往上提高產生障眼效果。提高過程可用絕對定位將遮罩層固定在底部,經過調整margin-bottom平移遮罩層。

爲了方便演示,註釋父容器的overflow:hidden,經過Chrome Devtools微調margin-bottom看看總體效果。後續記得將overflow:hidden聲明回來。

狀態懸浮球-原理2

.state-ball {
    // overflow: hidden;
    // ...
    &::before {
        position: absolute;
        left: 50%;
        bottom: 5px;
        z-index: 9;
        margin-left: -100px;
        margin-bottom: 0;
        border-radius: 100%;
        width: 200px;
        height: 200px;
        background-color: #09f;
        content: "";
    }
    // ...
}
複製代碼

爲了讓提高過程呈現動態效果,調整::before的背景顏色和圓角率並追加一個旋轉動畫。

狀態懸浮球-原理3

.state-ball {
    // ...
    &::before {
        position: absolute;
        left: 50%;
        bottom: 5px;
        z-index: 9;
        margin-left: -100px;
        margin-bottom: 0;
        border-radius: 45%;
        width: 200px;
        height: 200px;
        background-color: rgba(#fff, .5);
        content: "";
        animation: rotate 10s linear -5s infinite;
    }
    // ...
}
@keyframes rotate {
    to {
        transform: rotate(1turn);
    }
}
複製代碼

爲了讓波浪呈現立體效果,追加::after佔位並聲明總體樣式與::before一致,在背景顏色、圓角率和動畫時延上略有差別便可。另外聲明::aftermargin-bottom稍微比::before高一點,這樣在旋轉過程當中能讓波浪產生動態的立體效果。

在提高過程當中,兩個遮罩層位移距離應該是一致的,因此可用變量計算公式表示且::after::before10px。在這裏有個值得注意的地方,若變量結合calc()使用,其結果必須帶上單位,以這兩條公式爲例,其變量初始值必須爲--offset:0px,不能爲--offset:0

  • ::beforemargin-bottom:var(--offset)
  • ::aftermargin-bottom:calc(var(--offset) + 10px)

狀態懸浮球-原理4

<div class="state-ball" style="--offset: 0px;">
    <div class="wave"></div>
</div>
複製代碼
.state-ball {
    // ...
    &::before,
    &::after {
        position: absolute;
        left: 50%;
        bottom: 5px;
        z-index: 9;
        margin-left: -100px;
        width: 200px;
        height: 200px;
        content: "";
    }
    &::before {
        margin-bottom: var(--offset);
        border-radius: 45%;
        background-color: rgba(#fff, .5);
        animation: rotate 10s linear -5s infinite;
    }
    &::after {
        margin-bottom: calc(var(--offset) + 10px);
        border-radius: 40%;
        background-color: rgba(#fff, .8);
        animation: rotate 15s infinite;
    }
    // ...
}
// ...
複製代碼

到此再優化一些細節,經過Chrome Devtools檢查.wave得知其尺寸爲134x134,每次往上平移兩個僞元素只能1px那樣遞增。如今想將其平移100次就能填充整個球體,那麼就需按照134/100這個比例改造變量計算公式。

--offset聲明爲--offset:0,取值區間在0~100而不是0px~100px

  • ::beforemargin-bottom:calc(var(--offset) * 1.34px)
  • ::aftermargin-bottom:calc(var(--offset) * 1.34px + 10px)

狀態懸浮球-原理5

<div class="state-ball" style="--offset: 0;">
    <div class="wave"></div>
</div>
複製代碼
.state-ball {
    // ...
    &::before {
        margin-bottom: calc(var(--offset) * 1.34px)
        // ...
    }
    &::after {
        margin-bottom: calc(var(--offset) * 1.34px + 10px);
        // ...
    }
    // ...
}
// ...
複製代碼

如今已把位移距離控制在0~100的比例了,那麼剩下步驟就是追加一個<div>,使用其content存放在offset實時顯示進度了。

狀態懸浮球-原理6

<div class="state-ball" style="--offset: 0;">
    <div class="wave"></div>
    <div class="progress"></div>
</div>
複製代碼
.state-ball {
    // ...
    .progress::after {
        display: flex;
        position: absolute;
        left: 0;
        top: 0;
        z-index: 99;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100%;
        font-weight: bold;
        font-size: 16px;
        color: #09f;
        content: var(--offset) "%";
    }
}
// ...
複製代碼

但是發現無任何文本效果。狀況是這樣的,若變量是字符串類型可直接顯示,若變量是數值類型則需藉助counter()顯示。而counter()還需使用counter-reset初始默認值,CSS計數器怎樣用在這裏就不講解了,感興趣的同窗可自行百度。

總體改造工程就這樣完成了,完整代碼以下。最後經過JS操做變量--offset就能實時改變進度了。

狀態懸浮球

<div class="state-ball" style="--offset: 0;">
    <div class="wave"></div>
    <div class="progress"></div>
</div>
複製代碼
.state-ball {
    overflow: hidden;
    position: relative;
    padding: 5px;
    border: 3px solid #3c9;
    border-radius: 100%;
    width: 150px;
    height: 150px;
    background-color: #fff;
    &::before,
    &::after {
        position: absolute;
        left: 50%;
        bottom: 5px;
        z-index: 9;
        margin-left: -100px;
        width: 200px;
        height: 200px;
        content: "";
    }
    &::before {
        margin-bottom: calc(var(--offset) * 1.34px);
        border-radius: 45%;
        background-color: rgba(#fff, .5);
        animation: rotate 10s linear -5s infinite;
    }
    &::after {
        margin-bottom: calc(var(--offset) * 1.34px + 10px);
        border-radius: 40%;
        background-color: rgba(#fff, .8);
        animation: rotate 15s infinite;
    }
    .wave {
        position: relative;
        border-radius: 100%;
        width: 100%;
        height: 100%;
        background-image: linear-gradient(to bottom, #af8 13%, #3c9 91%);
    }
    .progress::after {
        display: flex;
        position: absolute;
        left: 0;
        top: 0;
        z-index: 99;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100%;
        font-weight: bold;
        font-size: 16px;
        color: #09f;
        content: counter(progress) "%";
        counter-reset: progress var(--offset);
    }
}
@keyframes rotate {
    to {
        transform: rotate(1turn);
    }
}
複製代碼

無所不能的模擬點擊事件

:checked做用於選項選中的表單節點,當<input>type設置成radiocheckbox時可用。不少同窗都會使用input:checked + div {}input:checked ~ div {}的操做模擬鼠標點擊事件。要讓input:checked + div {}input:checked ~ div {}起效,其HTML結構必須像如下那樣。

<input type="radio">
<div></div>
複製代碼

這樣就沒法分離結構與行爲了,致使CSS必須跟着HTML走,只能使用絕對定位將<input>固定到指定位置。使用<label>綁定<input>可將<input>的鼠標選擇事件轉移到<label>上,由<label>控制選中狀態。那麼HTML結構可改成如下那樣,此時的<input>可設置hidden隱藏起來,不參與任何排版。

<input type="radio" id="btn" hidden>
<div>
    <label for="btn">
</div>
複製代碼

<input>使用id<label>使用for關聯起來,而hidden使<input>隱藏起來,不佔用頁面任何位置,此時<label>放置在頁面任何位置都行。

input:checked + div {}
input:checked ~ div {}
複製代碼

有了這樣的思路,就很易實現一個純CSS標籤導航了。

標籤導航

<div class="tab-navbar">
    <input id="tab1" type="radio" name="tabs" hidden checked>
    <input id="tab2" type="radio" name="tabs" hidden>
    <input id="tab3" type="radio" name="tabs" hidden>
    <input id="tab4" type="radio" name="tabs" hidden>
    <nav>
        <label for="tab1">標題1</label>
        <label for="tab2">標題2</label>
        <label for="tab3">標題3</label>
        <label for="tab4">標題4</label>
    </nav>
    <main>
        <ul>
            <li>內容1</li>
            <li>內容2</li>
            <li>內容3</li>
            <li>內容4</li>
        </ul>
    </main>
</div>
複製代碼
.active {
    background-color: #3c9;
    color: #fff;
}
.tab-navbar {
    display: flex;
    overflow: hidden;
    flex-direction: column-reverse;
    border-radius: 10px;
    width: 300px;
    height: 400px;
    input {
        &:nth-child(1):checked {
            & ~ nav label:nth-child(1) {
                @extend .active;
            }
            & ~ main ul {
                background-color: #f66;
                transform: translate3d(0, 0, 0);
            }
        }
        &:nth-child(2):checked {
            & ~ nav label:nth-child(2) {
                @extend .active;
            }
            & ~ main ul {
                background-color: #66f;
                transform: translate3d(-25%, 0, 0);
            }
        }
        &:nth-child(3):checked {
            & ~ nav label:nth-child(3) {
                @extend .active;
            }
            & ~ main ul {
                background-color: #f90;
                transform: translate3d(-50%, 0, 0);
            }
        }
        &:nth-child(4):checked {
            & ~ nav label:nth-child(4) {
                @extend .active;
            }
            & ~ main ul {
                background-color: #09f;
                transform: translate3d(-75%, 0, 0);
            }
        }
    }
    nav {
        display: flex;
        height: 40px;
        background-color: #f0f0f0;
        line-height: 40px;
        text-align: center;
        label {
            flex: 1;
            cursor: pointer;
            transition: all 300ms;
        }
    }
    main {
        flex: 1;
        ul {
            display: flex;
            flex-wrap: nowrap;
            width: 400%;
            height: 100%;
            transition: all 300ms;
        }
        li {
            display: flex;
            justify-content: center;
            align-items: center;
            flex: 1;
            font-weight: bold;
            font-size: 20px;
            color: #fff;
        }
    }
}
複製代碼

筆者曾經發表過一篇《純CSS免費讓掘金社區擁有暗黑模式切換功能》,探討了:checked+/~filter的玩法,詳情請查看原文,在此就不囉嗦了。

暗黑模式

總結

來不及分享的內容,就用文章敘述完,那天看直播的掘友們,讓大家久等了。這幾年花了不少時間鑽研CSS,也許寫完本文就要對CSS告一段落了。雖然花了不少時間鑽研CSS,但也發佈了幾篇爆款CSS文章和一本CSS掘金小冊,也算是留下了這幾年的CSS學習成果了。

喜歡作的事情總不想留什麼遺憾。接下來也要將鑽研方向轉移到JS上了,仍是會像鑽研CSS那樣認真鑽研JS的性能優化設計模式數據算法三大裝逼套件。指望在2021年能有新的突破吧,也感謝掘金社區讓我學習到別人的知識和別人學習到個人知識。

分享源碼存放在筆者的Github上,有須要的同窗可拷貝一份。還有就是筆者向可愛美的小冊姐姐要了100份玩轉CSS的藝術之美六折優惠碼WmOrR0hR,對該小冊感興趣的同窗可瞭解一下喲!

CSS是一門天馬行空的語言,說它簡單也行說它困難也行。想了解更多純CSS特效,可回看筆者往期文章,也可瀏覽筆者我的官網的純CSS特效專輯,保證知足你的眼球。

結語

❤️關注+點贊+收藏+評論+轉發❤️,原創不易,鼓勵筆者創做更多高質量文章

關注公衆號IQ前端,一個專一於CSS/JS開發技巧的前端公衆號,更多前端小乾貨等着你喔

  • 關注後回覆資料免費領取學習資料
  • 關注後回覆進羣拉你進技術交流羣
  • 歡迎關注IQ前端,更多CSS/JS開發技巧只在公衆號推送

相關文章
相關標籤/搜索