前幾天我們提到,如果適用於文件的樣式表中,同時有多個符合條件的規則,對某個元素的某個屬性宣告了不同樣式而彼此衝突時,CSS就會透過Cascading這套流程判斷優先順序,決定最終要套用什麼樣式。
不過在比較優先順序之前,還需要先確認這些樣式表有沒有對某個元素宣告樣式,以及這些宣告是否有效。
規範將這個過程稱作Filtering(這裡翻成過濾)。
在過濾出有效的宣告時,會考量:[1]
經由過濾,可以篩選出適用於某個元素的某個屬性的有效宣告有哪些。這些宣告對元素屬性設定的值,就稱作屬性的宣告值(Declared values)。
當元素的屬性同時適用於多個宣告值,就會進入Cascading的流程,判斷這些宣告值的優先順序。
考量樣式表來源、重要性等因素後,最終選出的宣告值,稱作屬性的Cascaded value(最多只會有一個,所以value沒有加s)。
不過,不是每個屬性都會有Cascaded value。
如果屬性原本就沒有符合條件且有效的宣告值,經過Cascading後自然也不會有Cascaded value。
但這麼一來,就無法依據屬性值,決定元素要以什麼樣式呈現。
因此規範規定,瀏覽器等使用者代理程式在解析文件時,每個元素的每個屬性都必須賦予一個屬性值。[1]
假如元素的某個屬性沒有Cascaded value,就會依據這個屬性的值能否從上層元素繼承,決定要給屬性什麼預設值。
如果沒有可用的Cascaded value,,可以繼承的屬性會繼承上層元素的Computed Value(這裡翻成計算值)作為預設值;
無法繼承的屬性,則會以屬性原本的初始值(initial value)作為預設值;
如果繼承元素本身就是根元素,沒有上層元素可以繼承,同樣會以初始值作為預設值。
需要注意的是,由於是沒有Cascaded value時才會向上層元素繼承屬性值,針對元素本身宣告的屬性值始終會優先於可能繼承的預設值。
這個檢查屬性有沒有Cascaded value,如果沒有則依據屬性可否繼承決定預設值的過程,稱作Defaulting(這裡翻成預設化);
經由預設化得出的屬性值,稱作Specified Value(這裡翻成指定值)。
關於屬性是否可以繼承,還有屬性的初始值是什麼,可以參考規範結尾處的屬性索引Property index,或是MDN的CSS reference。
例如以下由規範Display Module Level 3提供的表格,說明了display預設無法繼承(inherited: no),且初始值為inline
(initial: inline)。
以下透過範例說明繼承與初始值。
在網頁中,以<section>
建立三個區塊,每個區塊裡用<p>
放入兩個段落。
<section class="styled">
<p>section 1</p>
<p class="styled">本身有設定文字顏色</p>
</section>
<section class="styled">
<p>section 2</p>
<p>本身沒有設定文字顏色</p>
</section>
<section>
<p>section 3</p>
<p>本身沒有設定文字顏色</p>
</section>
前兩個區塊添加了class
屬性,以選擇器section.styled
設定文字顏色、邊框跟邊距,跟第三個區塊做出區別;
第一個區塊裡的第二個<p>
也添加了class
屬性,以選擇器p.styled
設定文字顏色,跟其他段落做出區別。
section.styled {
color: blue;
border: 1px solid yellowgreen;
margin-top: 1px;
}
p.styled {
color: red;
}
由於color
是會繼承的屬性,即使前兩個區塊內的段落沒有設定文字顏色,也會繼承區塊設定的屬性值而變成藍色。
不過針對元素本身宣告的屬性值,始終優先於繼承來的屬性值。所以第一個區塊的第二個段落的文字顏色會是另外設定的紅色,而非預設會繼承的藍色。
如果沒有設定,屬性也不會繼承的話,預設值就會是初始值。
第三塊區塊沒有設定border
、margin-top
等不會繼承的屬性,這兩個屬性就會以初始值為預設值。所以沒有邊框,也沒有邊距。
得出指定值後,還需要經過處理,依序轉為計算值Computed Value、使用值Used Value,才會變成屬性最終的實際值Actual Value。[1]
指定值經過解析會變成計算值。在前面提到的屬性表格中,會定義怎麼解析出每個屬性的計算值。
此時通常會將相對單位計算為絕對值,但還不會考慮到佈局因素。比如說width
的計算值可能會是關鍵字auto
,但還需要考量上層元素的長度,才能計算出實際的長度。[2]
得到計算值後,會再考量佈局等因素,完成最後的計算。此時得出的絕對理論值稱作使用值。
像是長度相關的屬性,如果計算值是關鍵字如auto
或百分比如50%
,會再參考上層元素的佈局資訊,進一步換算成以px
為單位的絕對長度。[2]
得到使用值後,使用者代理程式可能會再考量環境等因素限制,調整原先的使用值,得出最終用於渲染的實際值。
像是有可能使用者代理程式只能以整數渲染邊框寬度,所以當使用值不是整數時,需要進一步四捨五入轉換為整數。[2]
得到最終的實際值後,瀏覽器就可以根據CSS屬性值,渲染出文件。
不過除了CSS,有些文件的標記語言可能也有自己用於設定樣式的方法。像是HTML可以另外透過bgcolor
屬性設定<body>
等元素的背景顏色。
如果同時透過兩種方式設定樣式,文件最終會怎麼呈現?
這些標記語言另外用於設定樣式的方法,規範稱作presentational hints(這裡翻成呈現提示)。
這些呈現提示會被使用者代理程式轉換為對應的CSS規則。之後同樣需要參與Cascading的流程,跟其他CSS宣告值一決勝負。
在判斷樣式表的來源時,這些呈現提示可能會被視作使用者代理樣式表,或是優先順序介於使用者樣式表與作者樣式表中間的作者呈現提示樣式表(author presentational hint origin)。[3]
至於要以哪種來源參與,標記語言也可以在規範中明定,讓使用者代理程式遵循。像是SVG就規定會以作者樣式表參與。
如果呈現提示是以使用者代理樣式表參與競爭,就可能會被作者樣式表或使用者樣式表設定的樣式蓋過;
如果是以作者呈現提示樣式表參與競爭,因為優先度比較低,可能也會作者樣式表的樣式蓋過。但仍然會優先於使用者樣式表的樣式。
如果呈現提示最終勝利,變成屬性的Cascaded value,同樣需要經過進一步處理為Actual Value,才能用於渲染文件。
我們今天介紹了CSS處理屬性值的流程。
如果對屬性宣告樣式,需要經過篩選,過濾出符合元素條件的宣告值。
這些宣告值需要以樣式表來源等因素淘選,找出其中最優先適用的作為屬性的Cascaded value。
如果屬性沒有Cascaded value,也會依據其是否為繼承屬性,決定要以繼承值或初始值作為預設的指定值。
得出指定值後,還需要經過使用者代理程式進一步處理,依序轉換為計算值、使用值跟實際值,才能用以渲染文件。
如果文件另外標記語言提供的其他方式設定樣式,則這些呈現提示會被轉換為CSS規則,同樣需要經歷Cascading等屬性處理流程。
不過,本來無法繼承的屬性,其實也有辦法讓他繼承;
或是在Cascading被刷掉的宣告值,也有可能讓他參加敗部復活賽,取得最終的勝利。
不過時間不多了,讓我們下集待續~
[1]: W3C, CSS Cascading and Inheritance Level 5, [Value Processing] (https://www.w3.org/TR/css-cascade-5/#value-stages)
[2]: MDN, CSS property value processing
[3]: W3C, CSS Cascading and Inheritance Level 5, [Precedence of Non-CSS Presentational Hints] (https://www.w3.org/TR/css-cascade-5/#preshint)