前端入門系列之CSS
- 2019 年 12 月 12 日
- 筆記
CSS (Cascading Style Sheets) 是用來樣式化和排版你的網頁的 —— 例如更改網頁內容的字體、顏色、大小和間距,將內容分割成多列或者加入動畫以及別的裝飾型效果。
CSS是什麼
CSS是一種用於向用戶指定文檔如何呈現的語言 — 它們如何被指定樣式、布局等。
文檔通常是用標記語言結構化的文本文件 — HTML 是最常用的標記語言, 但你依然可以遇見一些其他的標記語言,比如 SVG 或者 XML。
CSS如何影響HTML
Web瀏覽器將CSS規則應用於文檔以影響它們的顯示方式。一個CSS規則由以下組成:
- 一組 屬性 ,屬性的值更新了 HTML 的內容的顯示方式。比如,我想讓元素的寬度是其父元素的50%,或者元素背景變為紅色。
- 一個 選擇器,它選擇元素,這(些)元素是你想應用這些最新的屬性值於其上的元素。比如,我想將我的CSS規則應用到我HTML文檔中的所有段落上。
外部樣式表
外部樣式表是指:當你將你的 CSS 保存在一個獨立的擴展名為 .css 的文件中,並從HTML的 <link> 元素中引用它。此時 HTML 文件看起來像這樣:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>My CSS experiment</title> <link rel="stylesheet" href="style.css"> </head> <body> <h1>Hello World!</h1> <p>This is my first CSS example</p> </body> </html>
以及下面的 CSS 文件
h1 { color: blue; background-color: yellow; border: 1px solid black; } p { color: red; }這種方法可以說是最好的,因為你可以使用一個樣式表來設置多個文檔的樣式,並且需要更新 CSS 的時候只要在一個地方更新。
內部樣式表
內部樣式表是指不使用外部 CSS 文件,而是將你的 CSS 放置在<style> 元素中,該元素包含在 HTML head 內。此時HTML看起來像這樣:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>My CSS experiment</title> <style> h1 { color: blue; background-color: yellow; border: 1px solid black; } p { color: red; } </style> </head> <body> <h1>Hello World!</h1> <p>This is my first CSS example</p> </body> </html>這在某些情況下很有用(也許你正在使用一個內容管理系統,不能直接修改 CSS 文件),但它不如外部樣式表高效 —— 在網站中,CSS 將需要在每個頁面重複,並且需要更新時要更改的多個位置。
內聯樣式
內聯樣式是僅影響一個元素的CSS聲明,被 style 屬性包括著:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>My CSS experiment</title> </head> <body> <h1 style="color: blue;background-color: yellow;border: 1px solid black;">Hello World!</h1> <p style="color:red;">This is my first CSS example</p> </body> </html>
除非有必要,否則不要這麼做!這很難維護(你可能不得不在每份文檔里更新多次同樣的資訊),並且它還混合了 CSS 表示的樣式資訊和 HTML 的結構資訊,使 CSS 難以閱讀和理解。保持不同類型程式碼的分離和純凈使處理該程式碼的任何人工作更為容易。
您唯一可能需要使用內聯樣式是當您的工作環境真的非常受限(也許您的CMS只允許您編輯 HTML 的 body)。
CSS如何工作
當瀏覽器顯示文檔時,它必須將文檔的內容與其樣式資訊結合。它分兩個階段處理文檔:
DOM是什麼
HTML DOM 是關於如何獲取、修改、添加或刪除 HTML 元素的標準。它是一個抽象概念。(????)
讓我們假定下面這段HTML程式碼:
<p> Let's use: <span>Cascading</span> <span>Style</span> <span>Sheets</span> </p>
在該 DOM 中,我們的 <p> 元素所對應的節點是父節點。它的子節點是一個文本節點和我們的一些 <span> 元素對應的節點。這些 SPAN結點也是父節點,它們各自的文本節點就是它們的子節點:
P ├─ "Let's use:" ├─ SPAN | └─ "Cascading" ├─ SPAN | └─ "Style" └─ SPAN └─ "Sheets"
這就是瀏覽器解釋先前的HTML片段的過程 —它渲染上述的DOM樹,之後在瀏覽器中像這樣輸出它。
CSS語法
從最基本的層次來看,CSS是由兩塊內容組合而成的:
- 屬性(Property): 一些人類可理解的標識符,這些標識符指出你想修改哪一些樣式,例如:字體,寬度,背景顏色等。
- 屬性值(Value): 每個指定的屬性都需要給定一個值,這個值表示你想把那些樣式特徵修改成什麼樣,例如,你想把字體,寬度或背景顏色改成什麼。
與值配對的屬性被稱為CSS聲明。CSS聲明會被放置在一個CSS聲明塊中。最後,CSS聲明塊與選擇器相結合形成一個CSS規則集(或CSS規則)
CSS聲明
CSS 的屬性和屬性值都是區分大小寫的。屬性和屬性值之間,用英文半形冒號 (:) 隔離,如下圖所示。

css 語法 - 聲明
CSS 有超過300 個不同的屬性以及幾乎無窮無盡的屬性值。屬性和屬性值不能任意組合:每個屬性都有一個已經定義好的可用屬性值範圍。
重要: 如果使用了未知屬性,或者給屬性賦予了無效值,該聲明會被視為無效,瀏覽器的 CSS 引擎會完全忽略它。
重要: 在 CSS(和其他網路標準)中,使用美式拼寫作為單詞的標準寫法。例如,顏色(見於上述程式碼所見)應始終拼寫為 color。寫成 colour會無法正常工作。
CSS聲明塊
聲明按塊分組,每一組聲明都用一對大括弧包裹,用 ({) 開始,用 (}) 結束。
聲明塊里的每一個聲明必須用半形分號(;)分隔,否則程式碼會不生效(至少不會按預期結果生效)。聲明塊里的最後一個聲明結束的地方,不需要加分號,但是最後加分號是個好習慣,因為可以防止在後續增加聲明時忘記加分號。

注意: 塊有時候是可以嵌套的。這種情況下,每一對括弧必須邏輯上嵌套,跟嵌套 HTML 元素的標籤嵌套方式相同。最常見的例子是 _@-rules,_這是一種用 @ 標識開頭的塊,例如 @media, @font-face等(詳見下述的 CSS 語句)。
注意: 聲明塊的內容允許為空 —— 這完全有效。
CSS選擇器和規則
我們需要討論一下如何告知我們的聲明塊:哪些元素是它們需要應用的。通過在每個聲明塊前加上選擇器(selector) 來完成這一動作,選擇器是一種模式,它能在頁面上匹配一些元素。這將使相關的聲明僅被應用到被選擇的元素上。選擇器加上聲明塊被稱為 規則集(ruleset),通常簡稱規則(rule)。

CSS語句
CSS 規則只是被稱為 CSS 語句中的一種。
- @-規則(At-rules) 在CSS中被用來傳遞元數據、條件資訊或其它描述性資訊。它由(
@)符號開始,緊跟著一個表明它是哪種規則的描述符,之後是這種規則的語法塊,並最終由一個半形分號(;)結束。每種由描述符定義的@-規則,都有其特有的內部語法和語義。一些例子如下:@charset和@import(元數據)@media或@document(條件資訊,又被稱為嵌套語句,見下方。)@font-face(描述性資訊)具體語法示例:
@import 'custom.css'; 該@-規則向當前 CSS 導入其它 CSS 文件
- 嵌套語句 是@-規則中的一種,它的語法是 CSS 規則的嵌套塊,只有在特定條件匹配時才會應用到文檔上。特定條件如下:
@media只有在運行瀏覽器的設備匹配其表達條件時才會應用該@-規則的內容;@supports只有瀏覽器確實支援被測功能時才會應用該@-規則的內容;@document只有當前頁面匹配一些條件時才會應用該@-規則的內容。具體語法示例
@media (min-width: 801px) { body { margin: 0 auto; width: 800px; } } 上述的嵌套語句只有在頁面寬度超過801像素時才會應用。
CSS選擇器
選擇器可以被分為以下類別:
- 簡單選擇器(Simple selectors): 通過元素類型、
class或id匹配一個或多個元素。 - 屬性選擇器(Attribute selectors): 通過 屬性 / 屬性值 匹配一個或多個元素。
- 偽類(Pseudo-classes): 匹配處於確定狀態的一個或多個元素,比如被滑鼠指針懸停的元素,或當前被選中或未選中的複選框,或元素是DOM樹中一父節點的第一個子節點。
- 偽元素(Pseudo-elements): 匹配處於相關的確定位置的一個或多個元素,例如每個段落的第一個字,或者某個元素之前生成的內容。
- 組合器(Combinators): 這裡不僅僅是選擇器本身,還有以有效的方式組合兩個或更多的選擇器用於非常特定的選擇的方法。例如,你可以只選擇divs的直系子節點的段落,或者直接跟在headings後面的段落。
- 多重選擇器(Multiple selectors): 這些也不是單獨的選擇器;這個思路是將以逗號分隔開的多個選擇器放在一個CSS規則下面, 以將一組聲明應用於由這些選擇器選擇的所有元素。
簡單選擇器
1) 類選擇器 類選擇器由一個點「.」以及類後面的類名組成。類名是在HTML class文檔元素屬性中沒有空格的任何值。由你自己選擇一個名字。同樣值得一提的是,文檔中的多個元素可以具有相同的類名,而單個元素可以有多個類名(以空格分開多個類名的形式書寫)。
我們來看一個例子: 這是一些HTML:
<ul> <li class="first done">Create an HTML document</li> <li class="second done">Create a CSS style sheet</li> <li class="third">Link them all together</li> </ul>
這是一些CSS樣式:
/* The element with the class "first" is bolded */ .first { font-weight: bold; } /* All the elements with the class "done" are strike through */ .done { text-decoration: line-through; }效果:
- Create an HTML document
- Create a CSS style sheet
- Link them all together
2) 類型選擇器 此選擇器只是一個選擇器名和指定的HTML元素名的不區分大小寫的匹配。這是選擇所有指定類型的最簡單方式。讓我們一起看看下面這個例子:
這是HTML:
<p>What color do you like?</p> <div>I like blue.</div> <p>I prefer red!</p>
這是樣式表:
/* All p elements are red */ p { color: red; } /* All div elements are blue */ div { color: blue; }效果:
What color do you like?
I like blue.
I prefer red!
3) ID選擇器 ID選擇器是由一個哈希/磅符號 (#),後面跟著給定元素的ID名稱組成的。 任何元素都可以使用id屬性設置唯一的ID名稱。 由你自己決定選擇一個ID名稱是什麼。 這是選擇單個元素的最有效的方式。 重要提示:一個ID名稱必須在文檔中是唯一的。關於重複ID的行為是不可預測的,比如一些瀏覽器只是計入第一個實例,其餘的將被忽略。
我們來看一個簡單的例子 - 這是HTML:
<p id="polite"> — "Good morning."</p> <p id="rude"> — "Go away!"</p>
這是樣式表:
#polite { font-family: cursive; } #rude { font-family: monospace; text-transform: uppercase; }效果:
— "Good morning."
— "GO AWAY!"
4) 通用選擇器 通用選擇(*)是最終的王牌。它允許選擇在一個頁面中的所有元素。由於給每個元素應用同樣的規則幾乎沒有什麼實際價值,更常見的做法是與其他選擇器結合使用(參考下面 組合 .)
重要提示:使用通用選擇時小心。因為它適用於所有的元素,在大型網頁利用它可能對性能有明顯的影響:網頁可能顯示比預期要慢。大多數情況下,你都不會使用這個選擇器。
例如,這是HTML:
<div> <p>I think the containing box just needed a <strong>border</strong> or <em>something</em>, but this is getting <strong>out of hand</strong>!</p> </div>
這是樣式表:
* { padding: 5px; border: 1px solid black; background: rgba(255,0,0,0.25) }屬性選擇器
屬性選擇器是一種特殊類型的選擇器,它根據元素的屬性和屬性值來匹配元素。它們的通用語法由方括弧 ([]) 組成,其中包含屬性名稱,後跟可選條件以匹配屬性的值。 屬性選擇器可以根據其匹配屬性值的方式分為兩類: 存在和值屬性選擇器和子串值屬性選擇器。
1) 存在和值(Presence and value)屬性選擇器
這些屬性選擇器嘗試匹配精確的屬性值:
[attr]:該選擇器選擇包含 attr 屬性的所有元素,不論 attr 的值為何。[attr=val]:該選擇器僅選擇 attr 屬性被賦值為 val 的所有元素。[attr~=val]:該選擇器僅選擇具有 attr 屬性的元素,而且要求val值是attr值包含的被空格分隔的取值列表裡中的一個。
讓我們看一個特別的例子,下面是它的的HTML程式碼:
我的食譜配料: <i lang="fr-FR">Poulet basquaise</i> <ul> <li data-quantity="1kg" data-vegetable>Tomatoes</li> <li data-quantity="3" data-vegetable>Onions</li> <li data-quantity="3" data-vegetable>Garlic</li> <li data-quantity="700g" data-vegetable="not spicy like chili">Red pepper</li> <li data-quantity="2kg" data-meat>Chicken</li> <li data-quantity="optional 150g" data-meat>Bacon bits</li> <li data-quantity="optional 10ml" data-vegetable="liquid">Olive oil</li> <li data-quantity="25cl" data-vegetable="liquid">White wine</li> </ul>
和一個簡單的樣式表:
/* 所有具有"data-vegetable"屬性的元素將被應用綠色的文本顏色 */ [data-vegetable] { color: green } /* 所有具有"data-vegetable"屬性且屬性值剛好為"liquid"的元素將被應用金色的背景顏色 */ [data-vegetable="liquid"] { background-color: goldenrod; } /* 所有具有"data-vegetable"屬性且屬性值包含"spicy"的元素, 即使元素的屬性中還包含其他屬性值,都會被應用紅色的文本顏色 */ [data-vegetable~="spicy"] { color: red; }效果: TODO:
2) 子串值(Substring value)屬性選擇器 這種情況的屬性選擇器也被稱為「偽正則選擇器」,因為它們提供類似 regular expression 的靈活匹配方式(但請注意,這些選擇器並不是真正的正則表達式):
[attr|=val]: 選擇attr屬性的值是val或值以val-開頭的元素(注意,這裡的 「-」 不是一個錯誤,這是用來處理語言編碼的)。[attr^=val]: 選擇attr屬性的值以val開頭(包括val)的元素。[attr$=val]: 選擇attr屬性的值以val結尾(包括val)的元素。[attr*=val]: 選擇attr屬性的值中包含子字元串val的元素(一個子字元串就是一個字元串的一部分而已,例如,」cat「 是 字元串 」caterpillar「 的子字元串)。
讓我們繼續我們前面的例子,並添加以下CSS規則:
/* 語言選擇的經典用法 */ [lang|="fr"] { font-weight: bold; } /* 具有"data-vegetable"屬性含有值"not spicy"的所有元素,都變回綠色 */ [data-vegetable*="not spicy"] { color: green; } /* 具有"data-quantity"屬性其值以"kg"結尾的所有元素*/ [data-quantity$="kg"] { font-weight: bold; } /* 具有屬性"data-quantity"其值以"optional"開頭的所有元素 */ [data-quantity^="optional"] { opacity: 0.5; }效果: TODO:
偽類和偽元素
該選擇器不是選擇元素,而是元素的某些部分,或僅在某些特定上下文中存在的元素。它們有兩種主要類型 : 偽類和偽元素。 1)偽類 一個 CSS 偽類(pseudo-class) 是一個以冒號(:)作為前綴,被添加到一個選擇器末尾的關鍵字,當你希望樣式在特定狀態下才被呈現到指定的元素時,你可以往元素的選擇器後面加上對應的偽類(pseudo-class)。你可能希望某個元素在處於某種狀態下呈現另一種樣式,例如當滑鼠懸停在元素上面時,或者當一個複選框被禁用或被勾選時,又或者當一個元素是它在 DOM 樹中父元素的第一個子元素時。
現在,讓我們來看一個簡單的使用例子。首先是一個 HTML 片段:
<a href="https://developer.mozilla.org/" target="_blank">Mozilla Developer Network</a>
然後,一些 CSS 樣式:
/* 這些樣式將在任何情況下應用於我們 的鏈接 */ a { color: blue; font-weight: bold; } /* 我們想讓被訪問過的鏈接和未被訪問 的鏈接看起來一樣 */ a:visited { color: blue; } /* 當游標懸停於鏈接,鍵盤激活或鎖定 鏈接時,我們讓鏈接呈現高亮 */ a:hover, a:active, a:focus { color: darkred; text-decoration: none; }效果: TODO:
2)偽元素 偽元素(Pseudo-element)跟偽類很像,但它們又有不同的地方。它們都是關鍵字,但這次偽元素前綴是兩個冒號 (::) , 同樣是添加到選擇器後面去選擇某個元素的某個部分。
我們在這裡僅展示一個簡單的 CSS 例子,就是如何在所有超鏈接元素後面的增加一個箭頭:
<ul> <li><a href="https://developer.mozilla.org/en-US/docs/Glossary/CSS">CSS</a> defined in the MDN glossary.</li> <li><a href="https://developer.mozilla.org/en-US/docs/Glossary/HTML">HTML</a> defined in the MDN glossary.</li> </ul>
讓我們加上 CSS 規則:
/* 所有含有"href"屬性並且值以"http"開始的元素, 將會在其內容後增加一個箭頭(去表明它是外部鏈接) */ [href^=http]::after { content: '⤴'; }組合器和選擇器組
將多個選擇器組合在一起以進一步利用其選擇能力。
名稱 | -------組合器 | 選擇 |
|---|---|---|
選擇器組 | A,B | 匹配滿足A(和/或)B的任意元素(參見下方 同一規則集上的多個選擇器). |
後代選擇器 | A B | 匹配B元素,滿足條件:B是A的後代結點(B是A的子節點,或者A的子節點的子節點) |
子選擇器 | A > B | 匹配B元素,滿足條件:B是A的直接子節點 |
相鄰兄弟選擇器 | A + B | 匹配B元素,滿足條件:B是A的下一個兄弟節點(AB有相同的父結點,並且B緊跟在A的後面) |
通用兄弟選擇器 | A ~ B | 匹配B元素,滿足條件:B是A之後的任意一個兄弟節點(AB有相同的父節點,B在A之後,但不一定是緊挨著A) |
接下來看一個使用了組合器的例子:
<table lang="en-US" class="with-currency"> <thead> <tr> <th scope="col">Product</th> <th scope="col">Qty.</th> <th scope="col">Price</th> </tr> </thead> <tfoot> <tr> <th colspan="2" scope="row">Total:</th> <td>148.55</td> </tr> </tfoot> <tbody> <tr> <td>Lawnchair</td> <td>1</td> <td>137.00</td> </tr> <tr> <td>Marshmallow rice bar</td> <td>2</td> <td>1.10</td> </tr> <tr> <td>Book</td> <td>1</td> <td>10.45</td> </tr> </tbody> </table>
然後對該HTML文檔應用下面的樣式表:
/* 基本的table樣式(類型選擇器/元素選擇器/element selector) */ table { font: 1em sans-serif; border-collapse: collapse; border-spacing: 0; } /* 所有在table里的td以及th,這裡的逗號不是一個組合器, 它只是允許你把幾個選擇器對應到相同的CSS規則上.*/ table td, table th { border : 1px solid black; padding: 0.5em 0.5em 0.4em; } /* 所有table里的thead里的所有th */ table thead th { color: white; background: black; } /* 所有table里的tbody里的所有td(第一個除外),每個td都是由它上邊的td選擇 */ table tbody td + td { text-align: center; } /*table里所有的tbody里的td當中的最後一個 */ table tbody td:last-child { text-align: right } /* 所有table里的tfoot里的th */ table tfoot th { text-align: right; border-top-width: 5px; border-left: none; border-bottom: none; } /* 在table當中,所有的th之後的td */ table th + td { text-align: right; border-top-width: 5px; color: white; background: black; } /* 定位在「with-currency」類中擁有屬性lang並且這個屬性值為en-US的元素中的,最後td(:last-child)節點的前面(::before)*/ .with-currency[lang="en-US"] td:last-child::before { content: '$'; } /* 定位在「with-currency」類中擁有屬性lang並且這個屬性值為fr的元素中的,最後td(:last-child)節點的後面(::after) */ .with-currency[lang="fr"] td:last-child::after { content: ' €'; }表格如下:
Product | Qty. | Price |
|---|---|---|
Total: | 148.55 | |
Lawnchair | 1 | $137.00 |
Marshmallow rice bar | 2 | $1.10 |
Book | 1 | $10.45 |
Total: | $148.55 |
CSS數值和單位
數值:
p { margin: 5px; padding: 10px; border: 2px solid black; background-color: cyan; } p:nth-child(1) { width: 150px; font-size: 18px; } p:nth-child(2) { width: 250px; font-size: 24px; } p:nth-child(3) { width: 350px; font-size: 30px; }絕對單位
像素 (px) 是一種絕對單位(absolute units), 因為無論其他相關的設置怎麼變化,像素指定的值是不會變化的。其他的絕對單位如下:
mm,cm,in: 毫米(Millimeters),厘米(centimeters),英寸(inches)pt,pc: 點(Points (1/72 of an inch)), 十二點活字( picas (12 points.))
除了px之外,你很可能都不怎麼使用其他的單位。 絕對單位之間的關係如下: 1in = 2.54cm = 25.4mm = 72pt = 6pc
相對單位
em:1em與當前元素的字體大小相同(更具體地說,一個大寫字母M的寬度)。CSS樣式被應用之前,瀏覽器給網頁設置的默認基礎字體大小是16像素,這意味著對一個元素來說1em的計算值默認為16像素。但是要小心—em單位是會繼承父元素的字體大小,所以如果在父元素上設置了不同的字體大小,em的像素值就會變得複雜。現在不要過於擔心這個問題,我們將在後面的文章和模組中更詳細地介紹繼承和字體大小設置。em是Web開發中最常用的相對單位。ex,ch: 分別是小寫x的高度和數字0的寬度。這些並不像em那樣被普遍使用或很好地被支援。rem: REM(root em)和em以同樣的方式工作,但它總是等於默認基礎字體大小的尺寸;繼承的字體大小將不起作用,所以這聽起來像一個比em更好的選擇,雖然在舊版本的IE上不被支援(查看關於跨瀏覽器支援 Debugging CSS.)vw,vh: 分別是視口寬度的1/100和視口高度的1/100,其次,它不像rem那樣被廣泛支援。
無單位的值
在CSS中,你有時會遇到一些無單位的數值——這並不總是意味著錯誤,在某些情況下,使用無單位的數值是完全允許的。例如,如果你想讓一個元素完全去除邊距或者邊框,你可以使用無單位的0——因為不管單位是什麼,0就是0!
1 邊距
margin: 0;
2 行高
另一個例子是 line-height,設置元素中每行文本的高度。你可以使用單位設置特定的行的高度,但使用一個無單位的值往往更容易,它就像一個簡單的乘法因子。例如
下面的CSS:
p { line-height: 1.5; }這裡font-size的值為16px; 行高為font-size值的1.5倍,也就是24px。
3 動畫的值
p:hover { animation-name: rotate; animation-duration: 0.6s; animation-timing-function: linear; animation-iteration-count: 5; }animation-iteration-count: 5; ——此行控制著動畫啟動(這裡是指游標浮動至段落上時)後會執行多少次,而且這是一個簡單的,無單位,純數字(電腦中稱之為整型)。
百分比
首先,使用HTML標記創建兩個相似的盒子:
<div> <div class="boxes">Fixed width layout with pixels</div> <div class="boxes">Liquid layout with percentages</div> </div>
然後是一些CSS來裝飾這些盒子:
div .boxes { margin: 10px; font-size: 200%; color: white; height: 150px; border: 2px solid black; } .boxes:nth-child(1) { background-color: red; width: 650px; } .boxes:nth-child(2) { background-color: blue; width: 75%; }這兩種不同的框布局類型通常被稱為動態(流體)布局(跟隨瀏覽器視口大小的變化)和固定寬度布局(不管怎樣都保持不變),兩種布局方式有著不同的應用場景:
顏色
和iOS一樣,有一下幾種表示方式:
- 十六進位值
p:nth-child(1) { background-color: #ff0000; }- RGB:
p:nth-child(1) { background-color: rgb(255,0,0); }- HSL
p:nth-child(1) { background-color: hsl(0,100%,50%); }hsl()函數接受三個表示色調、飽和度以及亮度的參數
- RGBA, HSLA,增加一個alpha通道
層疊和繼承
有多個選擇器匹配到同一個元素上時,哪個選擇器的 CSS 規則最終會應用到元素上?其實這是通過層疊機制來控制的,這也和樣式繼承(元素從其父元素那裡獲得屬性值)有關。
層疊
CSS 是 Cascading Style Sheets 的縮寫,這暗示層疊(cascade)的概念是很重要的。在最基本的層面上,它表明CSS規則的順序很重要,但它比那更複雜。什麼選擇器在層疊中勝出取決於三個因素(這些都是按重量級順序排列的——前面的的一種會否決後一種):
- 重要性(Importance)
- 專用性(Specificity)
- 源程式碼次序(Source order)
1 重要性 在CSS中,有一個特別的語法可以讓一條規則總是優先於其他規則:!important。把它加在屬性值的後面可以使這條聲明有無比強大的力量。 顯示聲明重要性!
讓我們看一下這個例子:
<p class="better">This is a paragraph.</p> <p class="better" id="winning">One selector to rule them all!</p>
#winning { background-color: red; border: 1px solid black; } .better { background-color: gray; border: none !important; } p { background-color: blue; color: white; padding: 5px; }讓我們一起來看看發生了什麼。
- 你可以看到第三條規則
color和padding被運用了, 但background-color沒有,為什麼?實際上,這三種情況都應該應用,因為在源順序後面的規則通常會覆蓋較早的規則。 - 然而, 在前面的規則被運用了,因為 IDs/class 選擇器優先於element選擇器。 (對此,你將在下一章中學到更多)
- 這兩個元素都有
class並帶有better屬性, 但是第二個元素有id值為winning。 因為比起class而言id專用性更高(在一個頁面上id是唯一的, 但很多元素可以擁有相同的class — ID 選擇器在它們的目標中是非常優先的),紅色背景色和1pixel的黑色邊框都應應用於第二元素,第一個元素獲得灰色背景色,沒有邊框,如類所指定。 - 第二個元素獲得紅色背景色,但沒有邊框。為什麼?因為
!important在第二條規則中的聲明——在border: none之後寫入它意味著儘管id具有更高的優先性,該聲明也將優先於前面規則中的邊界值聲明。
不要使用 !important 我們建議你千萬不要使用它,除非你絕對必須使用它。由於 !important 改變了層疊正常工作的方式,因此調試CSS問題,尤其是在大型樣式表中,會變得非常困難。
衝突處理 要注意一個CSS聲明的重要性取決於它被指定在什麼樣式表內——用戶可以設置自定義樣式表覆蓋開發者的樣式,例如用戶可能有視力障礙,想設置字體大小對所有網頁的訪問是雙倍的正常大小,以便更容易閱讀。
相互衝突的聲明將按以下順序適用,後一種將覆蓋先前的聲明:
- 在用戶代理樣式表的聲明 (瀏覽器默認樣式).
- 用戶樣式表中的普通聲明(由用戶設置的自定義樣式)。
- 作者樣式表中的普通聲明(這是我們設置的樣式,Web開發人員)。
- 作者樣式表中的重要聲明(Web開發人員!important)
- 用戶樣式表中的重要聲明(用戶!important)
2 專用性 專用性基本上是衡量選擇器的具體程度的一種方法——它能匹配多少元素。如上面所示的示例所示,元素選擇器具有很低的專用性。類選擇器具有更高的專用性,所以將戰勝元素選擇器。ID選擇器有甚至更高的專用性, 所以將戰勝類選擇器. 戰勝ID選擇器的唯一方法是使用 !important。 選擇越唯一越專用!
一個選擇器具有的專用性的量是用四種不同的值(或組件)來衡量的,它們可以被認為是千位,百位,十位和個位——在四個列中的四個簡單數字:
- 千位:如果聲明是在
style屬性中該列加1分(這樣的聲明沒有選擇器,所以它們的專用性總是1000。)否則為0。 - 百位:在整個選擇器中每包含一個ID選擇器就在該列中加1分。
- 十位:在整個選擇器中每包含一個類選擇器、屬性選擇器、或者偽類就在該列中加1分。
- 個位:在整個選擇器中每包含一個元素選擇器或偽元素就在該列中加1分。
下表顯示了幾個示例。試著通過這些,並確保你理解他們為什麼具有我們給予他們的專用性。
選擇器 | 千位 | 百位 | 十位 | 個位 | 合計值 |
|---|---|---|---|---|---|
h1 | 0 | 0 | 0 | 1 | 0001 |
#indentifier | 0 | 1 | 0 | 0 | 0100 |
h1 + p::first-letter | 0 | 0 | 0 | 3 | 0003 |
li > a[href*="zh-CN"] > .inline-warning | 0 | 0 | 2 | 2 | 0022 |
沒有選擇器, 規則在一個元素的 <style> 屬性里 | 1 | 0 | 0 | 0 | 1000 |
在我們繼續之前,讓我們看看一個行動中的例子。這是我們將要使用的HTML:
<div id="outer" class="container"> <div id="inner" class="container"> <ul> <li class="nav"><a href="#">One</a></li> <li class="nav"><a href="#">Two</a></li> </ul> </div> </div>
下面是CSS的示例:
/* specificity: 0101 */ #outer a { background-color: red; } /* specificity: 0201 */ #outer #inner a { background-color: blue; } /* specificity: 0104 */ #outer div ul li a { color: yellow; } /* specificity: 0113 */ #outer div ul .nav a { color: white; } /* specificity: 0024 */ div div li:nth-child(2) a:hover { border: 10px solid black; } /* specificity: 0023 */ div li:nth-child(2) a:hover { border: 10px dashed black; } /* specificity: 0033 */ div div .nav:nth-child(2) a:hover { border: 10px double black; } a { display: inline-block; line-height: 40px; font-size: 20px; text-decoration: none; text-align: center; width: 200px; margin-bottom: 10px; } ul { padding: 0; } li { list-style-type: none; }這裡發生了什麼?首先,我們只對本例的前七個規則感興趣,正如您將注意到的,我們已經在每個注釋中包含了它們的專用性值。
- 前兩個選擇器正在競爭鏈接的背景顏色的樣式——第二個贏得並使背景色為藍色,因為它有一個額外的ID選擇器在鏈中:其專用性值為201比101。
- 第三個和第四個選擇器在鏈接文本顏色的樣式上進行競爭——第二個選擇器獲勝,使文本變白,因為缺少一個元素選擇器,缺少的選擇器被換成類選擇器,它的值是十,而不是個位。所以專用性值為113和104。
- 選擇器5 - 7在徘徊在鏈接附近時的樣式進行競爭。選擇器六明顯地輸給了了五,其專用性值為23和24——它在鏈中少了一個元素選擇器。然而選擇器七同時擊敗了五和六——它有與五相同數量的子選擇器在鏈中,但一個元素已被換為了一個類選擇器。所以獲勝的專用性值是33比23和24。
3 源程式碼次序 如上所述,如果多個相互競爭的選擇器具有相同的重要性和專用性,那麼第三個因素將幫助決定哪一個規則獲勝——後面的規則將戰勝先前的規則
注意:(屬性覆蓋其他屬性而不是規則凌駕於規則之上) 在考慮所有這些層疊理論和什麼樣式優先於其他樣式被應用時,你應該記住的一件事是,所有這些都發生在屬性級別上——屬性覆蓋其他屬性,但你不會讓整個規則凌駕於其他規則之上。
當多個CSS規則匹配相同的元素時,它們都被應用到該元素中。只有在這之後,任何相互衝突的屬性才會被評估,以確定哪種風格會戰勝其他類型。
層疊結束
繼承
應用於某個元素的一些屬性值將由該元素的子元素繼承,而有些則不會。
- 例如,對
font-family和color進行繼承是有意義的,因為這使得您可以很容易地設置一個站點範圍的基本字體,方法是應用一個字體到<html>元素;然後,您可以在需要的地方覆蓋單個元素的字體。如果要在每個元素上分別設置基本字體,那就太麻煩了。 - 再如,讓
margin,padding,border和background-image不被繼承是有意義的。想像一下,如果在容器元素上設置這些屬性並讓它們由每個子元素繼承,那麼樣式/布局會發生混亂,然後必須在每個單獨的元素上_取消_它們!
哪些屬性默認被繼承哪些不被繼承大部分符合常識。如果你想確定,你可以參考CSS參考資料—— 每個單獨的屬性頁都會從一個匯總表開始,其中包含有關該元素的各種詳細資訊,包括是否被繼承。
控制繼承
CSS為處理繼承提供了四種特殊的通用屬性值:
inherit: 該值將應用到選定元素的屬性值設置為與其父元素一樣。initial:該值將應用到選定元素的屬性值設置為與瀏覽器默認樣式表中該元素設置的值一樣。如果瀏覽器默認樣式表中沒有設置值,並且該屬性是自然繼承的,那麼該屬性值就被設置為inherit。unset:該值將屬性重置為其自然值,即如果屬性是自然繼承的,那麼它就表現得像inherit,否則就是表現得像initial。revert:如果當前的節點沒有應用任何樣式,則將該屬性恢復到它所擁有的值。換句話說,屬性值被設置成自定義樣式所定義的屬性(如果被設置), 否則屬性值被設置成用戶代理的默認樣式。(沒有應用任何樣式時,先使用自定義屬性,否則使用默認樣式)
inherit 值是最有趣的——它允許我們顯式地讓一個元素從其父類繼承一個屬性值。
讓我們看一個例子。首先有以下一段HTML:
<ul> <li>Default <a href="#">link</a> color</li> <li class="inherit">Inherit the <a href="#">link</a> color</li> <li class="initial">Reset the <a href="#">link</a> color</li> <li class="unset">Unset the <a href="#">link</a> color</li> </ul>
現在用CSS給它添加樣式:
body { color: green; } .inherit a { color: inherit; } .initial a { color: initial } .unset a { color: unset; }螢幕快照 2019-08-16 13.37.26
讓我們解釋這裡發生了什麼:
- 我們首先設置
<body>的color為綠色。 - 由於
color屬性是自然繼承的,所有的body子元素都會有相同的綠色。需要注意的是默認情況下瀏覽器設置鏈接的顏色為藍色,而不是自然繼承color屬性,因此在我們列表中的第一個鏈接是藍色的。 - 第二個規則設置一個類
inherit的元素內的鏈接,並從父類繼承它的顏色。在這種情況下, 意思是說鏈接繼承了父元素<li>的顏色,默認情況下<li>的顏色來自於它的父元素<ul>, 最後<ul>繼承自<body>元素,而<body>的color根據第一條規則設置成了綠色。 - 第三個規則選擇了在元素上使用類
initial的任意鏈接然後設置他們的顏色為initial。通常,initial的值被瀏覽器設置成了黑色,因此該鏈接被設置成了黑色。 - 最後一個規則選擇了在元素上使用類
unset的所有鏈接然後設置它們的顏色為unset——即我們不設置值。因為color屬性是一個自然繼承的屬性,它實際上就像把值設置成inherit一樣。結果是,該鏈接被設置成了與body一樣的顏色——綠色。