CSS 屬性值處理

對於文件樹中的每個元素,瀏覽器都會為適用於該元素的每個 CSS 屬性賦予一個值。給定元素或盒子的每個 CSS 屬性的渲染值是基於樣式表定義、繼承、層疊、依賴關係、單位轉換和顯示環境計算得出的結果。本指南透過探討指定值、計算值、使用值和實際值等關鍵概念,概述了用於定義每個 CSS 最終如何渲染的處理步驟。

屬性值

應用於元素或偽元素的每個樣式都基於單個 CSS 屬性宣告。每個 CSS 屬性只有一個值。應用的值由適用於該元素或偽元素的所有屬性宣告的層疊值決定,而應用的單個值來自於根據層疊演算法層疊排序中排名最高的屬性宣告。

當有多個宣告值時(即有多個宣告為同一元素提供相同或不同的屬性值),每個屬性值仍然必須來自單個屬性名-值對,因為每個屬性只應用一個值,即使該值是逗號分隔的值列表。

為了確定應用哪個宣告值,使用者代理會收集並處理來自不同來源的所有樣式,例如內聯樣式、內部和外部樣式表。

層疊決定了當多個相互衝突的樣式作用於同一元素時應該應用哪個值。層疊演算法定義了使用者代理如何組合源自不同來源、作用域和/或的屬性值。當選擇器匹配一個元素時,來自最高優先順序來源的屬性的宣告值將被應用,即使來自較低優先順序來源的選擇器具有更高的特異性

某些屬性會從其父元素繼承值,除非被顯式覆蓋。繼承可能在元素上特定屬性沒有樣式資訊時發生。如果該屬性是可繼承的,其值將設定為父元素的計算值。如果該屬性不可繼承,其值將設定為該元素的初始值

在逐步應用層疊規則和預設值之後,瀏覽器會確保視覺呈現與處理後的 CSS 相匹配。

處理概述

在深入瞭解各個值階段之前,瞭解值處理中發生的三個主要階段非常重要:篩選層疊預設

篩選

篩選是識別應用於每個元素的所有宣告的過程。一個宣告僅在以下情況下才適用於一個元素:

  • 該宣告屬於當前應用於本文件的樣式表
  • 任何包含該宣告的條件規則(如 @media@supports)當前為真。
  • 該宣告屬於其選擇器與該元素匹配的樣式規則
  • 該宣告在語法上是有效的:瀏覽器能識別該屬性名,並且值與該屬性的預期語法相匹配

只有有效的宣告才會成為宣告值。具有無效屬性名或無效值的宣告會根據 CSS 錯誤處理規則被過濾掉。

在此示例中,只有 font-sizefont-weight 宣告被處理。CSS 解析器會過濾掉錯誤,忽略或“過濾”掉具有無效屬性名的宣告。

css
p {
  font-size: 1.25em;
  colr: blue;
  font-weight: bold;
}

篩選完成後,每個元素對於每個 CSS 屬性都有零個或多個宣告值。這些宣告值是層疊處理階段的起點。

層疊

當多個宣告應用於同一元素的同一屬性時,層疊會解決這些衝突。層疊使用層疊排序演算法對宣告進行排序。

例如,兩個 font-size 宣告都匹配 <p class="large">CSS is fun!</p>,但第二個宣告被應用,因為它具有更高的特異性。兩個宣告都來自開發者樣式表,但第二個選擇器的特異性為 0-1-1,而第一個為 0-0-1

css
p {
  font-size: 1em;
}

p.large {
  font-size: 1.5em;
}

層疊之後,瀏覽器會為每個元素上的每個屬性確定層疊值。這個值將用於下一個處理階段:預設

預設

預設確保每個元素上的每個屬性都有一個值。這涉及在沒有 CSS 宣告顯式設定該屬性值時應用預設屬性值。這包括:

預設處理的結果是,每個屬性都保證有一個指定值

請注意,顯式預設關鍵字(initialinheritunsetrevertrevert-layer)也會被解析為其對應的值,以確定指定值

處理階段

作為文件扁平化元素樹一部分的所有元素都具有宣告值層疊值指定值計算值使用值實際值。對於某個特定屬性,這些值可能相同,也可能不同。例如,如果你的大型程式碼庫中包含 CSS p { font-size: 1.25em; },並且你的 HTML 中包含 <p class="large">CSS is fun!</p>,那麼這個段落的字號會是多少?font-size 值會經歷幾個階段,從 em 指定值變為渲染的 px 值。

值處理的階段是:

這些值用於確定最終的渲染值

宣告值

宣告值是來自應用於元素的宣告中任何語法有效的值。一個元素對於每個屬性可以有零個或多個宣告值。這些值來自樣式表(開發者、使用者或使用者代理),並在篩選階段被識別。

繼續我們的例子,其中我們的樣式表包含 p { font-size: 1.25em; },而連結到該樣式表的文件包含 <p class="large">CSS is fun!</p>。可能還有其他 font-size 宣告也可能應用於同一段落。使用者代理樣式表可能為所有段落設定 font-size: 1em,而另一個開發者宣告為具有 "large" 類的元素設定 font-size: 2em

css
/* User agent styles */
p {
  font-size: 1em;
}

/* author styles */
p {
  font-size: 1.25em;
}

.large {
  font-size: 2em;
}

我們的樣式表中可能還有許多其他的 font-size 宣告,但只有選擇器匹配該元素的宣告才會成為宣告值。在這個例子中,因為我們的 <p> 元素有 class="large",所以這三個宣告都是該元素的宣告值。

層疊值

層疊值是在層疊中勝出的宣告值。每個元素的每個屬性最多隻有一個層疊值。

在我們的宣告值中,開發者樣式勝過使用者代理樣式。在同一來源內,特異性更高的樣式勝過特異性更低的樣式。在這種情況下,層疊值將是 font-size: 2em,它來自開發者樣式表,特異性為 0-1-1

css
font-size: 2em;

如果一個屬性沒有宣告值,那麼它就沒有層疊值,這意味著該屬性的指定值將由預設過程確定。

指定值

指定值預設過程的結果。它保證在每個元素的每個屬性上都存在。指定值按以下方式確定:

  1. 如果存在層疊值,則層疊值就是指定值。
  2. 如果沒有層疊值,且該屬性是可繼承的,則指定值是父元素的計算值
  3. 如果沒有層疊值,且該屬性不可繼承,則指定值是該屬性的初始值

在我們的例子中,由於我們有一個 2em層疊值,這個值就成為了指定值。

css
font-size: 2em;

對於沒有層疊值的屬性,預設過程會確定其值。例如,如果未指定 color,由於它是一個可繼承屬性,color 會從父元素的計算值中繼承。如果未指定 margin,則會使用其初始0,因為 margin 不是可繼承屬性

css
color: inherit;
margin: 0;

初始值

一個屬性的初始值是其在規範的定義表中列出的預設值。在預設過程中,初始值在以下情況下使用:

  • 對於可繼承屬性,初始值僅在沒有層疊值時用於沒有父元素的根元素
  • 對於不可繼承屬性,初始值在沒有層疊值時用於所有元素

你可以透過使用 initial 關鍵字顯式設定初始值。

注意: 初始值可以在每個 CSS 屬性參考頁面的正式語法部分找到。例如,font-size 的初始值是 medium。初始值不應與瀏覽器樣式表指定的值混淆。

計算值

屬性的計算值是在繼承過程中從父元素傳遞給子元素的值。它是在將相對單位和自定義屬性等解析為絕對值之後,但在考慮佈局特定資訊之前的結果。

計算值由指定值計算得出,步驟如下:

  1. 處理特殊值 inheritinitialrevertrevert-layerunset
  2. 進行必要的計算,以達到屬性定義表中“計算值”行所描述的值。

得到屬性計算值所需的計算通常涉及將相對值(例如 em 單位或百分比)轉換為絕對值。例如,如果一個元素的指定值為 font-size: 16pxpadding-top: 2em,那麼 padding-top 的計算值就是 32px(字型大小的兩倍)。

然而,對於某些屬性(其中百分比是相對於可能需要佈局來確定的東西,例如 widthmargin-righttext-indenttop),以百分比指定的指定值會變成以百分比表示的計算值。此外,在 line-height 屬性上指定的無單位數字會成為計算值,如規範所述。這些在計算值中保留的相對值會在確定使用值時變為絕對值。

使用值

使用值是在對計算值執行所有計算,並用佈局特定的細節(例如,將百分比解析為實際畫素值)進行細化後的屬性值。

每個 CSS 屬性都有一個使用值。尺寸的使用值(例如 widthline-height)以畫素為單位。簡寫屬性的使用值(例如 background)與其元件屬性(例如 background-colorbackground-size)以及與 positionfloat 的值是一致的。

一個元素的 widthinline-size 的使用值是一個畫素值,即使該屬性的指定值是用百分比或關鍵字設定的。

如果我們有三個容器元素,其寬度分別設定為 auto50%inherit

css
#no-width {
  width: auto;
}

#width-50 {
  width: 50%;
}

#width-inherit {
  width: inherit;
}

/* Make results easier to see */
div {
  border: 1px solid red;
  padding: 8px;
}

雖然三個指定值 auto50%inherit 是關鍵字和 <percentage> 值,但使用 window.getComputedStyle(el)["width"]; 獲取的 width 返回的是一個絕對長度 px 值。

更改視窗大小或旋轉你的移動裝置以改變大小和使用值。

渲染值

渲染的值稱為實際值,而透過指令碼獲取的值稱為解析值

實際值

屬性的實際值是該屬性的使用值在應用了任何必要的近似處理之後的值。它是瀏覽器實現的最終渲染值,包括對渲染怪癖或限制的調整。例如,一個只能渲染整數畫素寬度邊框的使用者代理可能會將邊框的厚度四捨五入到最接近的整數。

計算包括以下步驟:

  1. 首先,根據層疊繼承的結果或使用初始值來確定指定值
  2. 接著,根據規範計算出計算值(例如,一個帶有 position: absolutespan 元素的計算 display 值會變為 block)。
  3. 然後,計算佈局,從而得到使用值
  4. 最後,根據本地環境的限制對使用值進行轉換,得到實際值。

解析值

屬性的解析值是在應用活動樣式表並解析這些值可能包含的任何基本計算之後的值。getComputedStyle() 方法返回一個即時的 CSSStyleDeclaration 物件,其中包含應用於指定元素的所有 CSS 屬性的解析值。每個解析值要麼是計算值,要麼是使用值,具體取決於屬性。

歷史上,getComputedStyle() 返回的是元素或偽元素的計算值。隨著 CSS 的發展,“計算值”的概念也在演變,但為了與已部署的指令碼向後相容,getComputedStyle() 返回的值必須保持不變。這些值就是“解析值”。

對於大多數屬性,解析值是計算值,但對於少數舊屬性(包括 widthheight),它是使用值。CSSOM 規範提供了每個屬性的詳細資訊。

CSS 2.0 將計算值定義為屬性計算的最後一步。CSS 2.1 引入了“使用值”的明確定義。一個元素因此可以明確地繼承其父元素的寬度/高度,而父元素的計算值是一個百分比。對於不依賴於佈局的 CSS 屬性(例如 displayfont-sizeline-height),計算值和使用值是相同的。以下列表包含了確實依賴於佈局的 CSS 2.1 屬性,因此它們具有不同的計算值和使用值(摘自 CSS 2.1 變更:指定值、計算值和實際值):

另見