CSS 基礎拾遺(核心知識、常見需求)

2023-04-21 18:00:48

本篇文章圍繞了 CSS 的核心知識點和專案中常見的需求來展開。雖然行文偏長,但較基礎,適合初級中級前端閱讀,閱讀的時候請適當跳過已經掌握的部分。

這篇文章斷斷續續寫了比較久,也參考了許多優秀的文章,但或許文章裡還是存在不好或不對的地方,請多多指教,可以評論裡直接提出來哈。

核心概念和知識點

語法

CSS 的核心功能是將 CSS 屬性設定為特定的值。一個屬性與值的鍵值對被稱為宣告(declaration)。

color: red;
複製程式碼

而如果將一個或者多個宣告用 {} 包裹起來後,那就組成了一個宣告塊(declaration block)。

{
    color: red;
    text-align: center;
}
複製程式碼

宣告塊如果需要作用到對應的 HTML 元素,那還需要加上選擇器。選擇器和宣告塊組成了CSS 規則集(CSS ruleset),常簡稱為 CSS 規則。

span {
    color: red;
    text-align: center;
}
複製程式碼

規則集中最後一條宣告可以省略分號,但是並不建議這麼做,因為容易出錯。

CSS 中的註釋

/* 單行註釋 */

/*
    多行
    註釋
*/
複製程式碼

在 CSS 檔案中,除了註釋、CSS 規則集以及 @規則 外,定義的一些別的東西都將被瀏覽器忽略。

@規則

CSS 規則是樣式表的主體,通常樣式表會包括大量的規則列表。但有時候也需要在樣式表中包括其他的一些資訊,比如字元集,匯入其它的外部樣式表,字型等,這些需要專門的語句表示。

而 @規則 就是這樣的語句。CSS 裡包含了以下 @規則:

  • @namespace 告訴 CSS 引擎必須考慮XML名稱空間。
  • @media, 如果滿足媒體查詢的條件則條件規則組裡的規則生效。
  • @page, 描述列印檔案時佈局的變化.
  • @font-face, 描述將下載的外部的字型。
  • @keyframes, 描述 CSS 動畫的關鍵幀。
  • @document, 如果檔案樣式表滿足給定條件則條件規則組裡的規則生效。 (推延至 CSS Level 4 規範)

除了以上這幾個之外,下面還將對幾個比較生澀的 @規則 進行介紹。

@charset

@charset 用於定義樣式表使用的字元集。它必須是樣式表中的第一個元素。如果有多個 @charset 被宣告,只有第一個會被使用,而且不能在HTML元素或HTML頁面的 <style> 元素內使用。

注意:值必須是雙引號包裹,且和

@charset "UTF-8";
複製程式碼

平時寫樣式檔案都沒寫 @charset 規則,那這個 CSS 檔案到底是用的什麼字元編碼的呢?

某個樣式表檔案到底用的是什麼字元編碼,瀏覽器有一套識別順序(優先順序由高到低):

  • 檔案開頭的 Byte order mark 字元值,不過一般編輯器並不能看到檔案頭裡的 BOM 值;

  • HTTP 響應頭裡的 content-type 欄位包含的 charset 所指定的值,比如:

    Content-Type: text/css; charset=utf-8
    複製程式碼
  • CSS 檔案頭裡定義的 @charset 規則裡指定的字元編碼;

  • <link> 標籤裡的 charset 屬性,該條已在 HTML5 中廢除;

  • 預設是 UTF-8

@import

@import 用於告訴 CSS 引擎引入一個外部樣式表。

link 和 @import 都能匯入一個樣式檔案,它們有什麼區別嘛?

  • link 是 HTML 標籤,除了能匯入 CSS 外,還能匯入別的資源,比如圖片、指令碼和字型等;而 @import 是 CSS 的語法,只能用來匯入 CSS;
  • link 匯入的樣式會在頁面載入時同時載入,@import 匯入的樣式需等頁面載入完成後再載入;
  • link 沒有相容性問題,@import 不相容 ie5 以下;
  • link 可以通過 JS 操作 DOM 動態引入樣式表改變樣式,而@import不可以。

@supports

@supports 用於查詢特定的 CSS 是否生效,可以結合 not、and 和 or 操作符進行後續的操作。

/* 如果支援自定義屬性,則把 body 顏色設定為變數 varName 指定的顏色 */
@supports (--foo: green) {
    body {
        color: var(--varName);
    }
}
複製程式碼

層疊性

層疊樣式表,這裡的層疊怎麼理解呢?其實它是 CSS 中的核心特性之一,用於合併來自多個源的屬性值的演演算法。比如說針對某個 HTML 標籤,有許多的 CSS 宣告都能作用到的時候,那最後誰應該起作用呢?層疊性說的大概就是這個。

針對不同源的樣式,將按照如下的順序進行層疊,越往下優先順序越高:

  • 使用者代理樣式表中的宣告(例如,瀏覽器的預設樣式,在沒有設定其他樣式時使用)。
  • 使用者樣式表中的常規宣告(由使用者設定的自定義樣式。由於 Chrome 在很早的時候就放棄了使用者樣式表的功能,所以這裡將不再考慮它的排序。)
  • 作者樣式表中的常規宣告(這些是我們 Web 開發人員設定的樣式)。
  • 作者樣式表中的 !important 宣告。
  • 使用者樣式表中的 !important 宣告S

理解層疊性的時候需要結合 CSS 選擇器的優先順序以及繼承性來理解。比如針對同一個選擇器,定義在後面的宣告會覆蓋前面的;作者定義的樣式會比預設繼承的樣式優先順序更高。

選擇器

CSS 選擇器無疑是其核心之一,對於基礎選擇器以及一些常用偽類必須掌握。下面列出了常用的選擇器。 想要獲取更多選擇器的用法可以看 MDN CSS Selectors

基礎選擇器

  • 標籤選擇器:h1
  • 類選擇器:.checked
  • ID 選擇器:#picker
  • 通配選擇器:*

屬性選擇器

  • [attr]:指定屬性的元素;
  • [attr=val]:屬性等於指定值的元素;
  • [attr*=val]:屬性包含指定值的元素;
  • [attr^=val] :屬性以指定值開頭的元素;
  • [attr$=val]:屬性以指定值結尾的元素;
  • [attr~=val]:屬性包含指定值(完整單詞)的元素(不推薦使用);
  • [attr|=val]:屬性以指定值(完整單詞)開頭的元素(不推薦使用);

組合選擇器

  • 相鄰兄弟選擇器:A + B
  • 普通兄弟選擇器:A ~ B
  • 子選擇器:A > B
  • 後代選擇器:A B

偽類

條件偽類

  • :lang():基於元素語言來匹配頁面元素;
  • :dir():匹配特定文字書寫方向的元素;
  • :has():匹配包含指定元素的元素;
  • :is():匹配指定選擇器列表裡的元素;
  • :not():用來匹配不符合一組選擇器的元素;

行為偽類

  • :active:滑鼠啟用的元素;
  • :hover: 滑鼠懸浮的元素;
  • ::selection:滑鼠選中的元素;

狀態偽類

  • :target:當前錨點的元素;
  • :link:未存取的連結元素;
  • :visited:已存取的連結元素;
  • :focus:輸入聚焦的表單元素;
  • :required:輸入必填的表單元素;
  • :valid:輸入合法的表單元素;
  • :invalid:輸入非法的表單元素;
  • :in-range:輸入範圍以內的表單元素;
  • :out-of-range:輸入範圍以外的表單元素;
  • :checked:選項選中的表單元素;
  • :optional:選項可選的表單元素;
  • :enabled:事件啟用的表單元素;
  • :disabled:事件禁用的表單元素;
  • :read-only:唯讀的表單元素;
  • :read-write:可讀可寫的表單元素;
  • :blank:輸入為空的表單元素;
  • :current():瀏覽中的元素;
  • :past():已瀏覽的元素;
  • :future():未瀏覽的元素;

結構偽類

  • :root:檔案的根元素;
  • :empty:無子元素的元素;
  • :first-letter:元素的首字母;
  • :first-line:元素的首行;
  • :nth-child(n):元素中指定順序索引的元素;
  • :nth-last-child(n):元素中指定逆序索引的元素;;
  • :first-child :元素中為首的元素;
  • :last-child :元素中為尾的元素;
  • :only-child:父元素僅有該元素的元素;
  • :nth-of-type(n) :標籤中指定順序索引的標籤;
  • :nth-last-of-type(n):標籤中指定逆序索引的標籤;
  • :first-of-type :標籤中為首的標籤;
  • :last-of-type:標籤中為尾標籤;
  • :only-of-type:父元素僅有該標籤的標籤;

偽元素

  • ::before:在元素前插入內容;
  • ::after:在元素後插入內容;

優先順序

優先順序就是分配給指定的 CSS 宣告的一個權重,它由匹配的選擇器中的每一種選擇器型別的數值決定。為了記憶,可以把權重分成如下幾個等級,數值越大的權重越高:

  • 10000:!important;
  • 01000:內聯樣式;
  • 00100:ID 選擇器;
  • 00010:類選擇器、偽類選擇器、屬性選擇器;
  • 00001:元素選擇器、偽元素選擇器;
  • 00000:通配選擇器、後代選擇器、兄弟選擇器;

可以看到內聯樣式(通過元素中 style 屬性定義的樣式)的優先順序大於任何選擇器;而給屬性值加上 !important 又可以把優先順序提至最高,就是因為它的優先順序最高,所以需要謹慎使用它,以下有些使用注意事項:

  • 一定要優先考慮使用樣式規則的優先順序來解決問題而不是 !important;
  • 只有在需要覆蓋全站或外部 CSS 的特定頁面中使用 !important;
  • 永遠不要在你的外掛中使用 !important;
  • 永遠不要在全站範圍的 CSS 程式碼中使用 !important;

繼承性

在 CSS 中有一個很重要的特性就是子元素會繼承父元素對應屬性計算後的值。比如頁面根元素 html 的文字顏色預設是黑色的,頁面中的所有其他元素都將繼承這個顏色,當申明瞭如下樣式後,H1 文字將變成橙色。

body {
    color: orange;
}
h1 {
    color: inherit;
}
複製程式碼

設想一下,如果 CSS 中不存在繼承性,那麼我們就需要為不同文字的標籤都設定一下 color,這樣一來的後果就是 CSS 的檔案大小就會無限增大。

CSS 屬性很多,但並不是所有的屬性預設都是能繼承父元素對應屬性的,那哪些屬性存在預設繼承的行為呢?一定是那些不會影響到頁面佈局的屬性,可以分為如下幾類:

  • 字型相關:font-familyfont-stylefont-sizefont-weight 等;
  • 文字相關:text-aligntext-indenttext-decorationtext-shadowletter-spacingword-spacingwhite-spaceline-heightcolor 等;
  • 列表相關:list-stylelist-style-imagelist-style-typelist-style-position 等;
  • 其他屬性:visibilitycursor 等;

對於其他預設不繼承的屬性也可以通過以下幾個屬性值來控制繼承行為:

  • inherit:繼承父元素對應屬性的計算值;
  • initial:應用該屬性的預設值,比如 color 的預設值是 #000
  • unset:如果屬性是預設可以繼承的,則取 inherit 的效果,否則同 initial
  • revert:效果等同於 unset,相容性差。

檔案流

在 CSS 的世界中,會把內容按照從左到右、從上到下的順序進行排列顯示。正常情況下會把頁面分割成一行一行的顯示,而每行又可能由多列組成,所以從視覺上看起來就是從上到下從左到右,而這就是 CSS 中的流式佈局,又叫檔案流。檔案流就像水一樣,能夠自適應所在的容器,一般它有如下幾個特性:

  • 塊級元素預設會佔滿整行,所以多個塊級盒子之間是從上到下排列的;
  • 內聯元素預設會在一行裡一列一列的排布,當一行放不下的時候,會自動切換到下一行繼續按照列排布;

如何脫離檔案流呢?

脫流檔案流指節點脫流正常檔案流後,在正常檔案流中的其他節點將忽略該節點並填補其原先空間。檔案一旦脫流,計算其父節點高度時不會將其高度納入,脫流節點不佔據空間。有兩種方式可以讓元素脫離檔案流:浮動和定位。

  • 使用浮動(float)會將元素脫離檔案流,移動到容器左/右側邊界或者是另一個浮動元素旁邊,該浮動元素之前佔用的空間將被別的元素填補,另外浮動之後所佔用的區域不會和別的元素之間發生重疊;
  • 使用絕對定位(position: absolute;)或者固定定位(position: fixed;)也會使得元素脫離檔案流,且空出來的位置將自動被後續節點填補。

盒模型

在 CSS 中任何元素都可以看成是一個盒子,而一個盒子是由 4 部分組成的:內容(content)、內邊距(padding)、邊框(border)和外邊距(margin)。

盒模型有 2 種:標準盒模型和 IE 盒模型,本別是由 W3C 和 IExplore 制定的標準。

如果給某個元素設定如下樣式:

.box {
    width: 200px;
    height: 200px;
    padding: 10px;
    border: 1px solid #eee;
    margin: 10px;
}
複製程式碼

標準盒模型認為:盒子的實際尺寸 = 內容(設定的寬/高) + 內邊距 + 邊框

所以 .box 元素內容的寬度就為 200px,而實際的寬度則是 width + padding-left + padding-right + border-left-width + border-right-width = 200 + 10 + 10 + 1 + 1 = 222。

IE 盒模型認為:盒子的實際尺寸 = 設定的寬/高 = 內容 + 內邊距 + 邊框

.box 元素所佔用的實際寬度為 200px,而內容的真實寬度則是 width - padding-left - padding-right - border-left-width - border-right-width = 200 - 10 - 10 - 1 - 1 = 178。

現在高版本的瀏覽器基本上預設都是使用標準盒模型,而像 IE6 這種老古董才是預設使用 IE 盒模型的。

在 CSS3 中新增了一個屬性 box-sizing,允許開發者來指定盒子使用什麼標準,它有 2 個值:

  • content-box:標準盒模型;
  • border-box:IE 盒模型;

視覺格式化模型

視覺格式化模型(Visual formatting model)是用來處理和在視覺媒體上顯示檔案時使用的計算規則。CSS 中一切皆盒子,而視覺格式化模型簡單來理解就是規定這些盒子應該怎麼樣放置到頁面中去,這個模型在計算的時候會依賴到很多的因素,比如:盒子尺寸、盒子型別、定位方案(是浮動還是定位)、兄弟元素或者子元素以及一些別的因素。

Visual formatting model

從上圖中可以看到視覺格式化模型涉及到的內容很多,有興趣深入研究的可以結合上圖看這個 W3C 的檔案 Visual formatting model。所以這裡就簡單介紹下盒子型別。

盒子型別由 display 決定,同時給一個元素設定 display 後,將會決定這個盒子的 2 個顯示型別(display type):

  • outer display type(對外顯示):決定了該元素本身是如何佈局的,即參與何種格式化上下文;
  • inner display type(對內顯示):其實就相當於把該元素當成了容器,規定了其內部子元素是如何佈局的,參與何種格式化上下文;

outer display type

對外顯示方面,盒子型別可以分成 2 類:block-level box(塊級盒子) 和 inline-level box(行內級盒子)。

依據上圖可以列出都有哪些塊級和行內級盒子:

  • 塊級盒子:display 為 block、list-item、table、flex、grid、flow-root 等;
  • 行內級盒子:display 為 inline、inline-block、inline-table 等;

所有塊級盒子都會參與 BFC,呈現垂直排列;而所有行內級盒子都參會 IFC,呈現水平排列。

除此之外,block、inline 和 inline-block 還有什麼更具體的區別呢?

block

  • 佔滿一行,預設繼承父元素的寬度;多個塊元素將從上到下進行排列;
  • 設定 width/height 將會生效;
  • 設定 padding 和 margin 將會生效;

inline

  • 不會佔滿一行,寬度隨著內容而變化;多個 inline 元素將按照從左到右的順序在一行裡排列顯示,如果一行顯示不下,則自動換行;
  • 設定 width/height 將不會生效;
  • 設定豎直方向上的 padding 和 margin 將不會生效;

inline-block

  • 是行內塊元素,不單獨佔滿一行,可以看成是能夠在一行裡進行左右排列的塊元素;
  • 設定 width/height 將會生效;
  • 設定 padding 和 margin 將會生效;

inner display type

對內方面,其實就是把元素當成了容器,裡面包裹著文字或者其他子元素。container box 的型別依據 display 的值不同,分為 4 種:

  • block container:建立 BFC 或者 IFC;
  • flex container:建立 FFC;
  • grid container:建立 GFC;
  • ruby container:接觸不多,不做介紹。

值得一提的是如果把 img 這種替換元素(replaced element)申明為 block 是不會產生 container box 的,因為替換元素比如 img 設計的初衷就僅僅是通過 src 把內容替換成圖片,完全沒考慮過會把它當成容器。

參考:

格式化上下文

格式化上下文(Formatting Context)是 CSS2.1 規範中的一個概念,大概說的是頁面中的一塊渲染區域,規定了渲染區域內部的子元素是如何排版以及相互作用的。

不同型別的盒子有不同格式化上下文,大概有這 4 類:

  • BFC (Block Formatting Context) 塊級格式化上下文;
  • IFC (Inline Formatting Context) 行內格式化上下文;
  • FFC (Flex Formatting Context) 彈性格式化上下文;
  • GFC (Grid Formatting Context) 格柵格式化上下文;

其中 BFC 和 IFC 在 CSS 中扮演著非常重要的角色,因為它們直接影響了網頁佈局,所以需要深入理解其原理。

BFC

塊格式化上下文,它是一個獨立的渲染區域,只有塊級盒子參與,它規定了內部的塊級盒子如何佈局,並且與這個區域外部毫不相干。

圖來源於 yachen168

BFC 渲染規則

  • 內部的盒子會在垂直方向,一個接一個地放置;
  • 盒子垂直方向的距離由 margin 決定,屬於同一個 BFC 的兩個相鄰盒子的 margin 會發生重疊;
  • 每個元素的 margin 的左邊,與包含塊 border 的左邊相接觸(對於從左往右的格式化,否則相反),即使存在浮動也是如此;
  • BFC 的區域不會與 float 盒子重疊;
  • BFC 就是頁面上的一個隔離的獨立容器,容器裡面的子元素不會影響到外面的元素。反之也如此。
  • 計算 BFC 的高度時,浮動元素也參與計算。

如何建立 BFC?

  • 根元素:html
  • 非溢位的可見元素:overflow 不為 visible
  • 設定浮動:float 屬性不為 none
  • 設定定位:position 為 absolute 或 fixed
  • 定義成塊級的非塊級元素:display: inline-block/table-cell/table-caption/flex/inline-flex/grid/inline-grid

BFC 應用場景

1、 自適應兩欄佈局

應用原理:BFC 的區域不會和浮動區域重疊,所以就可以把側邊欄固定寬度且左浮動,而對右側內容觸發 BFC,使得它的寬度自適應該行剩餘寬度。

<div class="layout">
    <div class="aside">aside</div>
    <div class="main">main</div>
</div>
複製程式碼
.aside {
    float: left;
    width: 100px;
}
.main {
    <!-- 觸發 BFC -->
    overflow: auto;
}
複製程式碼

2、清除內部浮動

浮動造成的問題就是父元素高度坍塌,所以清除浮動需要解決的問題就是讓父元素的高度恢復正常。而用 BFC 清除浮動的原理就是:計算 BFC 的高度時,浮動元素也參與計算。只要觸發父元素的 BFC 即可。

.parent {
    overflow: hidden;
}
複製程式碼

3、 防止垂直 margin 合併

BFC 渲染原理之一:同一個 BFC 下的垂直 margin 會發生合併。所以如果讓 2 個元素不在同一個 BFC 中即可阻止垂直 margin 合併。那如何讓 2 個相鄰的兄弟元素不在同一個 BFC 中呢?可以給其中一個元素外面包裹一層,然後觸發其包裹層的 BFC,這樣一來 2 個元素就不會在同一個 BFC 中了。

<div class="layout">
    <div class="a">a</div>
    <div class="contain-b">
        <div class="b">b</div>
    </div>
</div>
複製程式碼
.demo3 .a,
.demo3 .b {
    border: 1px solid #999;
    margin: 10px;
}
.contain-b {
    overflow: hidden;
}
複製程式碼

針對以上 3 個 範例 ,可以結合這個 BFC 應用範例 配合觀看更佳。

參考:CSS 原理 - Formatting Context

IFC

IFC 的形成條件非常簡單,塊級元素中僅包含內聯級別元素,需要注意的是當IFC中有塊級元素插入時,會產生兩個匿名塊將父元素分割開來,產生兩個 IFC。

IFC 渲染規則

  • 子元素在水平方向上一個接一個排列,在垂直方向上將以容器頂部開始向下排列;
  • 節點無法宣告寬高,其中 margin 和 padding 在水平方向有效在垂直方向無效;
  • 節點在垂直方向上以不同形式對齊;
  • 能把在一行上的框都完全包含進去的一個矩形區域,被稱為該行的線盒(line box)。線盒的寬度是由包含塊(containing box)和與其中的浮動來決定;
  • IFC 中的 line box 一般左右邊貼緊其包含塊,但 float 元素會優先排列。
  • IFC 中的 line box 高度由 line-height 計算規則來確定,同個 IFC 下的多個 line box 高度可能會不同;
  • 當內聯級盒子的總寬度少於包含它們的 line box 時,其水平渲染規則由 text-align 屬性值來決定;
  • 當一個內聯盒子超過父元素的寬度時,它會被分割成多盒子,這些盒子分佈在多個 line box 中。如果子元素未設定強制換行的情況下,inline box 將不可被分割,將會溢位父元素。

針對如上的 IFC 渲染規則,你是不是可以分析下下面這段程式碼的 IFC 環境是怎麼樣的呢?

<p>It can get <strong>very complicated</storng> once you start looking into it.</p>
複製程式碼

對應上面這樣一串 HTML 分析如下:

  • p 標籤是一個 block container,對內將產生一個 IFC;
  • 由於一行沒辦法顯示完全,所以產生了 2 個線盒(line box);線盒的寬度就繼承了 p 的寬度;高度是由裡面的內聯盒子的 line-height 決定;
  • It can get:匿名的內聯盒子;
  • very complicated:strong 標籤產生的內聯盒子;
  • once you start:匿名的內聯盒子;
  • looking into it.:匿名的內聯盒子。

參考:Inline formatting contexts

IFC 應用場景

  • 水平居中:當一個塊要在環境中水平居中時,設定其為 inline-block 則會在外層產生 IFC,通過 text-align 則可以使其水平居中。
  • 垂直居中:建立一個 IFC,用其中一個元素撐開父元素的高度,然後設定其 vertical-align: middle,其他行內元素則可以在此父元素下垂直居中。

偷個懶,demo 和圖我就不做了。

層疊上下文

在電腦顯示螢幕上的顯示的頁面其實是一個三維的空間,水平方向是 X 軸,豎直方向是 Y 軸,而螢幕到眼睛的方向可以看成是 Z 軸。眾 HTML 元素依據自己定義的屬性的優先順序在 Z 軸上按照一定的順序排開,而這其實就是層疊上下文所要描述的東西。

-w566

我們對層疊上下文的第一印象可能要來源於 z-index,認為它的值越大,距離螢幕觀察者就越近,那麼層疊等級就越高,事實確實是這樣的,但層疊上下文的內容遠非僅僅如此:

  • z-index 能夠在層疊上下文中對元素的堆疊順序其作用是必須配合定位才可以;
  • 除了 z-index 之外,一個元素在 Z 軸上的顯示順序還受層疊等級和層疊順序影響;

在看層疊等級和層疊順序之前,我們先來看下如何產生一個層疊上下文,特定的 HTML 元素或者 CSS 屬性產生層疊上下文,MDN 中給出了這麼一個列表,符合以下任一條件的元素都會產生層疊上下文:

  • html 檔案根元素
  • 宣告 position: absolute/relative 且 z-index 值不為 auto 的元素;
  • 宣告 position: fixed/sticky 的元素;
  • flex 容器的子元素,且 z-index 值不為 auto;
  • grid 容器的子元素,且 z-index 值不為 auto;
  • opacity 屬性值小於 1 的元素;
  • mix-blend-mode 屬性值不為 normal 的元素;
  • 以下任意屬性值不為 none 的元素:
    • transform
    • filter
    • perspective
    • clip-path
    • mask / mask-image / mask-border
  • isolation 屬性值為 isolate 的元素;
  • -webkit-overflow-scrolling 屬性值為 touch 的元素;
  • will-change 值設定了任一屬性而該屬性在 non-initial 值時會建立層疊上下文的元素;
  • contain 屬性值為 layout、paint 或包含它們其中之一的合成值(比如 contain: strict、contain: content)的元素。

層疊等級

層疊等級指節點在三維空間 Z 軸上的上下順序。它分兩種情況:

  • 在同一個層疊上下文中,它描述定義的是該層疊上下文中的層疊上下文元素在 Z 軸上的上下順序;
  • 在其他普通元素中,它描述定義的是這些普通元素在 Z 軸上的上下順序;

普通節點的層疊等級優先由其所在的層疊上下文決定,層疊等級的比較只有在當前層疊上下文中才有意義,脫離當前層疊上下文的比較就變得無意義了。

層疊順序

在同一個層疊上下文中如果有多個元素,那麼他們之間的層疊順序是怎麼樣的呢?

以下這個列表越往下層疊優先順序越高,視覺上的效果就是越容易被使用者看到(不會被其他元素覆蓋):

  • 層疊上下文的 border 和 background
  • z-index < 0 的子節點
  • 標準流內塊級非定位的子節點
  • 浮動非定位的子節點
  • 標準流內行內非定位的子節點
  • z-index: auto/0 的子節點
  • z-index > 0的子節點

如何比較兩個元素的層疊等級?

  • 在同一個層疊上下文中,比較兩個元素就是按照上圖的介紹的層疊順序進行比較。
  • 如果不在同一個層疊上下文中的時候,那就需要比較兩個元素分別所處的層疊上下文的等級。
  • 如果兩個元素都在同一個層疊上下文,且層疊順序相同,則在 HTML 中定義越後面的層疊等級越高。

參考:徹底搞懂CSS層疊上下文、層疊等級、層疊順序、z-index

值和單位

CSS 的宣告是由屬性和值組成的,而值的型別有許多種:

  • 數值:長度值 ,用於指定例如元素 width、border-width、font-size 等屬性的值;
  • 百分比:可以用於指定尺寸或長度,例如取決於父容器的 width、height 或預設的 font-size;
  • 顏色:用於指定 background-color、color 等;
  • 座標位置:以螢幕的左上角為座標原點定位元素的位置,比如常見的 background-position、top、right、bottom 和 left 等屬性;
  • 函數:用於指定資源路徑或背景圖片的漸變,比如 url()、linear-gradient() 等;

而還有些值是需要帶單位的,比如 width: 100px,這裡的 px 就是表示長度的單位,長度單位除了 px 外,比較常用的還有 em、rem、vw/vh 等。那他們有什麼區別呢?又應該在什麼時候使用它們呢?

px

螢幕解析度是指在螢幕的橫縱方向上的畫素點數量,比如解析度 1920×1080 意味著水平方向含有 1920 個畫素數,垂直方向含有 1080 個畫素數。

而 px 表示的是 CSS 中的畫素,在 CSS 中它是絕對的長度單位,也是最基礎的單位,其他長度單位會自動被瀏覽器換算成 px。但是對於裝置而言,它其實又是相對的長度單位,比如寬高都為 2px,在正常的螢幕下,其實就是 4 個畫素點,而在裝置畫素比(devicePixelRatio) 為 2 的 Retina 螢幕下,它就有 16 個畫素點。所以螢幕尺寸一致的情況下,螢幕解析度越高,顯示效果就越細膩。

講到這裡,還有一些相關的概念需要理清下:

裝置畫素(Device pixels)

裝置螢幕的物理畫素,表示的是螢幕的橫縱有多少畫素點;和螢幕解析度是差不多的意思。

裝置畫素比(DPR)

裝置畫素比表示 1 個 CSS 畫素等於幾個物理畫素。

計算公式:DPR = 物理畫素數 / 邏輯畫素數;

在瀏覽器中可以通過 window.devicePixelRatio 來獲取當前螢幕的 DPR。

畫素密度(DPI/PPI)

畫素密度也叫顯示密度或者螢幕密度,縮寫為 DPI(Dots Per Inch) 或者 PPI(Pixel Per Inch)。從技術角度說,PPI 只存在於計算機顯示領域,而 DPI 只出現於列印或印刷領域。

計算公式:畫素密度 = 螢幕對角線的畫素尺寸 / 物理尺寸

比如,對於解析度為 750 * 1334 的 iPhone 6 來說,它的畫素密度為:

Math.sqrt(750 * 750 + 1334 * 1334) / 4.7 = 326ppi
複製程式碼

裝置獨立畫素(DIP)

DIP 是特別針對 Android裝置而衍生出來的,原因是安卓螢幕的尺寸繁多,因此為了顯示能儘量和裝置無關,而提出的這個概念。它是基於螢幕密度而計算的,認為當螢幕密度是 160 的時候,px = DIP。

計算公式:dip = px * 160 / dpi

em

em 是 CSS 中的相對長度單位中的一個。居然是相對的,那它到底是相對的誰呢?它有 2 層意思:

  • 在 font-size 中使用是相對於父元素的 font-size 大小,比如父元素 font-size: 16px,當給子元素指定 font-size: 2em 的時候,經過計算後它的字型大小會是 32px;
  • 在其他屬性中使用是相對於自身的字型大小,如 width/height/padding/margin 等;

我們都知道每個瀏覽器都會給 HTML 根元素 html 設定一個預設的 font-size,而這個值通常是 16px。這也就是為什麼 1em = 16px 的原因所在了。

em 在計算的時候是會層層計算的,比如:

<div>
    <p></p>
</div>
複製程式碼
div { font-size: 2em; }
p { font-size: 2em; }
複製程式碼

對於如上一個結構的 HTML,由於根元素 html 的字型大小是 16px,所以 p 標籤最終計算出來後的字型大小會是 16 * 2 * 2 = 64px

rem

rem(root em) 和 em 一樣,也是一個相對長度單位,不過 rem 相對的是 HTML 的根元素 html。

rem 由於是基於 html 的 font-size 來計算,所以通常用於自適應網站或者 H5 中。

比如在做 H5 的時候,前端通常會讓 UI 給 750px 寬的設計圖,而在開發的時候可以基於 iPhone X 的尺寸 375px * 812px 來寫頁面,這樣一來的話,就可以用下面的 JS 依據當前頁面的視口寬度自動計算出根元素 html 的基準 font-size 是多少。

(function (doc, win) {
    var docEl = doc.documentElement,
        resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
        psdWidth = 750,  // 設計圖寬度
        recalc = function () {
            var clientWidth = docEl.clientWidth;
            if ( !clientWidth ) return;
            if ( clientWidth >= 640 ) {
                docEl.style.fontSize = 200 * ( 640 / psdWidth ) + 'px';
            } else {
                docEl.style.fontSize = 200 * ( clientWidth / psdWidth ) + 'px';
            }
        };

    if ( !doc.addEventListener ) return;
    // 繫結事件的時候最好配合防抖函數
    win.addEventListener( resizeEvt, debounce(recalc, 1000), false );
    doc.addEventListener( 'DOMContentLoaded', recalc, false );
    
    function debounce(func, wait) {
        var timeout;
        return function () {
            var context = this;
            var args = arguments;
            clearTimeout(timeout)
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
})(document, window);
複製程式碼

比如當視口是 375px 的時候,經過計算 html 的 font-size 會是 100px,這樣有什麼好處呢?好處就是方便寫樣式,比如從設計圖量出來的 header 高度是 50px 的,那我們寫樣式的時候就可以直接寫:

header {
    height: 0.5rem;
}
複製程式碼

每個從設計圖量出來的尺寸只要除於 100 即可得到當前元素的 rem 值,都不用經過計算,非常方便。偷偷告訴你,如果你把上面那串計算 html 標籤 font-size 的 JS 程式碼中的 200 替換成 2,那在計算 rem 的時候就不需要除於 100 了,從設計圖量出多大 px,就直接寫多少個 rem。

vw/vh

vw 和 vh 分別是相對於螢幕視口寬度和高度而言的長度單位:

  • 1vw = 視口寬度均分成 100 份中 1 份的長度;
  • 1vh = 視口高度均分成 100 份中 1 份的長度;

在 JS 中 100vw = window.innerWidth,100vh = window.innerHeight。

vw/vh 的出現使得多了一種寫自適應佈局的方案,開發者不再侷限於 rem 了。

相對視口的單位,除了 vw/vh 外,還有 vmin 和 vmax:

  • vmin:取 vw 和 vh 中值較小的;
  • vmax:取 vw 和 vh 中值較大的;

顏色體系

CSS 中用於表示顏色的值種類繁多,足夠構成一個體系,所以這裡就專門拿出一個小節來講解它。

根據 CSS 顏色草案 中提到的顏色值型別,大概可以把它們分為這幾類:

  • 顏色關鍵字
  • transparent 關鍵字
  • currentColor 關鍵字
  • RGB 顏色
  • HSL 顏色

顏色關鍵字

顏色關鍵字(color keywords)是不區分大小寫的識別符號,它表示一個具體的顏色,比如 white(白),黑(black)等;

可接受的關鍵字列表在CSS的演變過程中發生了改變:

  • CSS 標準 1 只接受 16 個基本顏色,稱為 VGA 顏色,因為它們來源於 VGA 顯示卡所顯示的顏色集合而被稱為 VGA colors (視訊圖形陣列色彩)。
  • CSS 標準 2 增加了 orange 關鍵字。
  • 從一開始,瀏覽器接受其它的顏色,由於一些早期瀏覽器是 X11 應用程式,這些顏色大多數是 X11 命名的顏色列表,雖然有一點不同。SVG 1.0 是首個正式定義這些關鍵字的標準;CSS 色彩標準 3 也正式定義了這些關鍵字。它們經常被稱作擴充套件的顏色關鍵字, X11 顏色或 SVG 顏色 。
  • CSS 顏色標準 4 新增可 rebeccapurple 關鍵字來紀念 web 先鋒 Eric Meyer。

如下這張圖是 16 個基礎色,又叫 VGA 顏色。截止到目前為止 CSS 顏色關鍵字總共有 146 個,這裡可以檢視 完整的色彩關鍵字列表

VGA 顏色

需要注意的是如果宣告的時候的顏色關鍵字是錯誤的,瀏覽器會忽略它。

transparent 關鍵字

transparent 關鍵字表示一個完全透明的顏色,即該顏色看上去將是背景色。從技術上說,它是帶有 alpha 通道為最小值的黑色,是 rgba(0,0,0,0) 的簡寫。

透明關鍵字有什麼應用場景呢?

實現三角形

下面這個圖是用 4 條邊框填充的正方形,看懂了它你大概就知道該如何用 CSS 寫三角形了。

div {
    border-top-color: #ffc107;
    border-right-color: #00bcd4;
    border-bottom-color: #e26b6b;
    border-left-color: #cc7cda;
    border-width: 50px;
    border-style: solid;
}
複製程式碼

用 transparent 實現三角形的原理:

  • 首先寬高必須是 0px,通過邊框的粗細來填充內容;
  • 那條邊需要就要加上顏色,而不需要的邊則用 transparent;
  • 想要什麼樣姿勢的三角形,完全由上下左右 4 條邊的中有顏色的邊和透明的邊的位置決定;
  • 等腰三角形:設定一條邊有顏色,然後緊挨著的 2 邊是透明,且寬度是有顏色邊的一半;直角三角形:設定一條邊有顏色,然後緊挨著的任何一邊透明即可。

看下範例:

增大點選區域

常常在行動端的時候點選的按鈕的區域特別小,但是由於現實效果又不太好把它做大,所以常用的一個手段就是通過透明的邊框來增大按鈕的點選區域:

.btn {
    border: 5px solid transparent;
}
複製程式碼

currentColor 關鍵字

currentColor 會取當前元素繼承父級元素的文字顏色值或宣告的文字顏色值,即 computed 後的 color 值。

比如,對於如下 CSS,該元素的邊框顏色會是 red:

.btn {
    color: red;
    border: 1px solid currentColor;
}
複製程式碼

RGB[A] 顏色

RGB[A] 顏色是由 R(red)-G(green)-B(blue)-A(alpha) 組成的色彩空間。

在 CSS 中,它有兩種表示形式:

  • 十六進位制符號;
  • 函數符;

十六進位制符號

RGB 中的每種顏色的值範圍是 00~ff,值越大表示顏色越深。所以一個顏色正常是 6 個十六進位制字元加上 # 組成,比如紅色就是 #ff0000。

如果 RGB 顏色需要加上不透明度,那就需要加上 alpha 通道的值,它的範圍也是 00~ff,比如一個帶不透明度為 67% 的紅色可以這樣寫 #ff0000aa。

使用十六進位制符號表示顏色的時候,都是用 2 個十六進位製表示一個顏色,如果這 2 個字元相同,還可以縮減成只寫 1 個,比如,紅色 #f00;帶 67% 不透明度的紅色 #f00a。

函數符

當 RGB 用函數表示的時候,每個值的範圍是 0~255 或者 0%~100%,所以紅色是 rgb(255, 0, 0), 或者 rgb(100%, 0, 0)。

如果需要使用函數來表示帶不透明度的顏色值,值的範圍是 0~1 及其之間的小數或者 0%~100%,比如帶 67% 不透明度的紅色是 rgba(255, 0, 0, 0.67) 或者 rgba(100%, 0%, 0%, 67%)

需要注意的是 RGB 這 3 個顏色值需要保持一致的寫法,要嘛用數位要嘛用百分比,而不透明度的值的可以不用和 RGB 保持一致寫法。比如 rgb(100%, 0, 0) 這個寫法是無效的;而 rgb(100%, 0%, 0%, 0.67) 是有效的。

在第 4 代 CSS 顏色標準中,新增了一種新的函數寫法,即可以把 RGB 中值的分隔逗號改成空格,而把 RGB 和 alpha 中的逗號改成 /,比如帶 67% 不透明度的紅色可以這樣寫 rgba(255 0 0 / 0.67)。另外還把 rgba 的寫法合併到 rgb 函數中了,即 rgb 可以直接寫帶不透明度的顏色。

HSL[A] 顏色

HSL[A] 顏色是由色相(hue)-飽和度(saturation)-亮度(lightness)-不透明度組成的顏色體系。

  • 色相(H)是色彩的基本屬性,值範圍是 0360 或者 0deg360deg, 0 (或 360) 為紅色, 120 為綠色, 240 為藍色;
  • 飽和度(S)是指色彩的純度,越高色彩越純,低則逐漸變灰,取 0~100% 的數值;0% 為灰色, 100% 全色;
  • 亮度(L),取 0~100%,0% 為暗,100% 為白;
  • 不透明度(A),取 0100%,或者01及之間的小數;

寫法上可以參考 RGB 的寫法,只是引數的值不一樣。

給一個按鈕設定不透明度為 67% 的紅色的 color 的寫法,以下全部寫法效果一致:

button {
    color: #ff0000aa;
    color: #f00a;
    color: rgba(255, 0, 0, 0.67);
    color: rgb(100% 0% 0% / 67%);
    color: hsla(0, 100%, 50%, 67%);
    color: hsl(0deg 100% 50% / 67%);
}
複製程式碼

小提示:在 Chrome DevTools 中可以按住 shift + 滑鼠左鍵可以切換顏色的表示方式。

媒體查詢

媒體查詢是指標對不同的裝置、特定的裝置特徵或者引數進行客製化化的修改網站的樣式。

你可以通過給 <link> 加上 media 屬性來指定該樣式檔案只能對什麼裝置生效,不指定的話預設是 all,即對所有裝置都生效:

<link rel="stylesheet" src="styles.css" media="screen" />
<link rel="stylesheet" src="styles.css" media="print" />
複製程式碼

都支援哪些裝置型別?

  • all:適用於所有裝置;
  • print:適用於在預覽列印模式下在螢幕上檢視的分頁材料和檔案;
  • screen:主要用於螢幕;
  • speech:主要用於語音合成器。

需要注意的是:通過 media 指定的 資源儘管不匹配它的裝置型別,但是瀏覽器依然會載入它。

除了通過 <link> 讓指定裝置生效外,還可以通過 @media 讓 CSS 規則在特定的條件下才能生效。響應式頁面就是使用了 @media 才讓一個頁面能夠同時適配 PC、Pad 和手機端。

@media (min-width: 1000px) {}
複製程式碼

媒體查詢支援邏輯操作符:

  • and:查詢條件都滿足的時候才生效;
  • not:查詢條件取反;
  • only:整個查詢匹配的時候才生效,常用語相容舊瀏覽器,使用時候必須指定媒體型別;
  • 逗號或者 or:查詢條件滿足一項即可匹配;

媒體查詢還支援眾多的媒體特性,使得它可以寫出很複雜的查詢條件:

/* 使用者裝置的最小高度為680px或為縱向模式的螢幕裝置 */
@media (min-height: 680px), screen and (orientation: portrait) {}
複製程式碼

常見需求

自定義屬性

之前我們通常是在前處理器裡才可以使用變數,而現在 CSS 裡也支援了變數的用法。通過自定義屬性就可以在想要使用的地方參照它。

自定義屬性也和普通屬性一樣具有級聯性,申明在 :root 下的時候,在全檔案範圍內可用,而如果是在某個元素下申明自定義屬性,則只能在它及它的子元素下才可以使用。

自定義屬性必須通過 --x 的格式申明,比如:--theme-color: red; 使用自定義屬性的時候,需要用 var 函數。比如:

<!-- 定義自定義屬性 -->
:root {
    --theme-color: red;
}

<!-- 使用變數 -->
h1 {
    color: var(--theme-color);
}
複製程式碼

上圖這個是使用 CSS 自定義屬性配合 JS 實現的動態調整元素的 box-shadow,具體可以看這個 codepen demo

1px 邊框解決方案

Retina 顯示屏比普通的螢幕有著更高的解析度,所以在行動端的 1px 邊框就會看起來比較粗,為了美觀通常需要把這個線條細化處理。這裡有篇文章列舉了 7 中方案可以參考一下:7種方法解決行動端Retina螢幕1px邊框問題

而這裡附上最後一種通過偽類和 transform 實現的相對完美的解決方案:

只設定單條底部邊框:

.scale-1px-bottom {
    position: relative;
    border:none;
}
.scale-1px-bottom::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: 0;
    background: #000;
    width: 100%;
    height: 1px;
    -webkit-transform: scaleY(0.5);
    transform: scaleY(0.5);
    -webkit-transform-origin: 0 0;
    transform-origin: 0 0;
}
複製程式碼

同時設定 4 條邊框:

.scale-1px {
    position: relative;
    margin-bottom: 20px;
    border:none;
}
.scale-1px::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    border: 1px solid #000;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    width: 200%;
    height: 200%;
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
    -webkit-transform-origin: left top;
    transform-origin: left top;
}
複製程式碼

清除浮動

什麼是浮動:浮動元素會脫離檔案流並向左/向右浮動,直到碰到父元素或者另一個浮動元素。

為什麼要清楚浮動,它造成了什麼問題?

因為浮動元素會脫離正常的檔案流,並不會佔據檔案流的位置,所以如果一個父元素下面都是浮動元素,那麼這個父元素就無法被浮動元素所撐開,這樣一來父元素就丟失了高度,這就是所謂的浮動造成的父元素高度坍塌問題。

父元素高度一旦坍塌將對後面的元素佈局造成影響,為了解決這個問題,所以需要清除浮動,讓父元素恢復高度,那該如何做呢?

這裡介紹兩種方法:通過 BFC 來清除、通過 clear 來清除。

BFC 清除浮動

前面介紹 BFC 的時候提到過,計算 BFC 高度的時候浮動子元素的高度也將計算在內,利用這條規則就可以清楚浮動。

假設一個父元素 parent 內部只有 2 個子元素 child,且它們都是左浮動的,這個時候 parent 如果沒有設定高度的話,因為浮動造成了高度坍塌,所以 parent 的高度會是 0,此時只要給 parent 創造一個 BFC,那它的高度就能恢復了。

而產生 BFC 的方式很多,我們可以給父元素設定overflow: auto 來簡單的實現 BFC 清除浮動,但是為了相容 IE 最好用 overflow: hidden。

.parent {
    overflow: hidden;
}
複製程式碼

通過 overflow: hidden 來清除浮動並不完美,當元素有陰影或存在下拉式選單的時候會被截斷,所以該方法使用比較侷限。

通過 clear 清除浮動

我先把結論貼出來:

.clearfix {
    zoom: 1;
}
.clearfix::after {
    content: "";
    display: block;
    clear: both;
}
複製程式碼

這種寫法的核心原理就是通過 ::after 偽元素為在父元素的最後一個子元素後面生成一個內容為空的塊級元素,然後通過 clear 將這個偽元素移動到所有它之前的浮動元素的後面,畫個圖來理解一下。

可以結合這個 codepen demo 一起理解上圖的 clear 清楚浮動原理。

上面這個 demo 或者圖裡為了展示需要所以給偽元素的內容設定為了 ::after,實際使用的時候需要設定為空字串,讓它的高度為 0,從而父元素的高度都是由實際的子元素撐開。

該方式基本上是現在人人都在用的清除浮動的方案,非常通用。

參考:CSS中的浮動和清除浮動,梳理一下

消除瀏覽器預設樣式

針對同一個型別的 HTML 標籤,不同的瀏覽器往往有不同的表現,所以在網站製作的時候,開發者通常都是需要將這些瀏覽器的預設樣式清除,讓網頁在不同的瀏覽器上能夠保持一致。

針對清除瀏覽器預設樣式這件事,在很早之前 CSS 大師 Eric A. Meyer 就幹過。它就是寫一堆通用的樣式用來重置瀏覽器預設樣式,這些樣式通常會放到一個命名為 reset.css 檔案中。比如大師的 reset.css 是這麼寫的:

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
    display: block;
}
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
    content: '';
    content: none;
}
table {
    border-collapse: collapse;
    border-spacing: 0;
}
複製程式碼

他的這份 reset.css 據說是被使用最廣泛的重設樣式的方案了。

除了 reset.css 外,後來又出現了 Normalize.css 。關於 Normalize.css, 其作者 necolas 專門寫了一篇文章介紹了它,並談到了它和 reset.css 的區別。這個是他寫那篇文章的翻譯版:讓我們談一談 Normalize.css

文章介紹到:Normalize.css 只是一個很小的CSS檔案,但它在預設的 HTML 元素樣式上提供了跨瀏覽器的高度一致性。相比於傳統的 CSS reset,Normalize.css 是一種現代的、為 HTML5 準備的優質替代方案,現在已經有很多知名的框架和網站在使用它了。

Normalize.css 的具體樣式可以看這裡 Normalize.css

區別於 reset.css,Normalize.css 有如下特點:

  • reset.css 幾乎為所有標籤都設定了預設樣式,而 Normalize.css 則是有選擇性的保護了部分有價值的預設值;
  • 修復了很多瀏覽器的 bug,而這是 reset.css 沒做到的;
  • 不會讓你的偵錯工具變的雜亂,相反 reset.css 由於設定了很多預設值,所以在瀏覽器偵錯工具中往往會看到一大堆的繼承樣式,顯得很雜亂;
  • Normalize.css 是模組化的,所以可以選擇性的去掉永遠不會用到的部分,比如表單的一般化;
  • Normalize.css 有詳細的說明檔案;

長文書處理

預設:字元太長溢位了容器

字元超出部分換行

字元超出位置使用連字元

單行文字超出省略

多行文字超出省略

檢視以上這些方案的範例: codepen demo

有意思的是剛好前兩天看到 chokcoco 針對文字溢位也寫了一篇文章,主要突出的是對整塊的文字溢位處理。啥叫整塊文字?比如,下面這種技術標籤就是屬於整塊文字:

另外他還對 iOS/Safari 做了相容處理,感興趣的可以去閱讀下:CSS 整塊文字溢位省略特性探究

水平垂直居中

讓元素在父元素中呈現出水平垂直居中的形態,無非就 2 種情況:

  • 單行的文字、inline 或者 inline-block 元素;
  • 固定寬高的塊級盒子;
  • 不固定寬高的塊級盒子;

以下列到的所有水平垂直居中方案這裡寫了個 codepen demo,配合範例閱讀效果更佳。

單行的文字、inline 或 inline-block 元素

水平居中

此類元素需要水平居中,則父級元素必須是塊級元素(block level),且父級元素上需要這樣設定樣式:

.parent {
    text-align: center;
}
複製程式碼

垂直居中

方法一:通過設定上下內間距一致達到垂直居中的效果:

.single-line {
    padding-top: 10px;
    padding-bottom: 10px;
}
複製程式碼

方法二:通過設定 heightline-height 一致達到垂直居中:

.single-line {
    height: 100px;
    line-height: 100px;
}
複製程式碼

固定寬高的塊級盒子

方法一:absolute + 負 margin

方法二:absolute + margin auto

方法三:absolute + calc

不固定寬高的塊級盒子

這裡列了 6 種方法,參考了顏海鏡 寫的文章 ,其中的兩種 line-height 和 writing-mode 方案看後讓我驚呼:還有這種操作?學到了學到了。

方法一:absolute + transform

方法二:line-height + vertical-align

方法三:writing-mode

方法四:table-cell

方法五:flex

方法六:grid

常用佈局

兩欄佈局(邊欄定寬主欄自適應)

針對以下這些方案寫了幾個範例: codepen demo

方法一:float + overflow(BFC 原理)

方法二:float + margin

方法三:flex

方法四:grid

三欄佈局(兩側欄定寬主欄自適應)

針對以下這些方案寫了幾個範例: codepen demo

方法一:聖盃佈局

方法二:雙飛翼佈局

方法三:float + overflow(BFC 原理)

方法四:flex

方法五:grid

多列等高佈局

結合範例閱讀更佳:codepen demo

方法一:padding + 負margin

方法二:設定父級背景圖片

三行佈局(頭尾定高主欄自適應)

列了 4 種方法,都是基於如下的 HTML 和 CSS 的,結合範例閱讀效果更佳:codepen demo

<div class="layout">
    <header></header>
    <main>
        <div class="inner"></div>
    </main>
    <footer></footer>
</div>
複製程式碼
html,
body,
.layout {
    height: 100%;
}
body {
    margin: 0;
}
header, 
footer {
    height: 50px;
}
main {
    overflow-y: auto;
}
複製程式碼

方法一:calc

方法二:absolute

方法三:flex

方法四:grid

 

作者:大海我來了
連結:https://juejin.cn/post/6941206439624966152
來源:稀土掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。