深入理解CSS屬性值語法
萬維網(wǎng)聯(lián)盟(W3C) 使用了一套特別的語法來定義 CSS 的屬性值,能讓所有的 CSS 屬性都用。如果你曾看過 CSS 規(guī)范,你可能已經(jīng)見過這套語法了。就像 border-image-slice
的語法 ,讓我們看看:
<'border-image-slice'> = [<number> | <percentage>]{1,4} && fill?
如果你不知道這些符號(hào)以及它們?nèi)绾喂ぷ鞯脑?,這套語法可能非常難理解。然而,這值得花時(shí)間來學(xué)。如果你理解 W3C 是如何定義這些屬性值的,你就可以理解 W3C CSS 規(guī)范 中任意一個(gè)了。
巴科斯范式
首先,我們看看巴科斯范式(Backus-Naur Form),因?yàn)檫@能幫我們理解 W3C 的屬性值語法。
Backus–Naur Form (BNF) 是用來描述計(jì)算機(jī)語言語法的正式符號(hào)集。它被設(shè)計(jì)得很清晰,所以在語言如何表達(dá)方面不會(huì)造成二義或者模糊。
最初 Backus-Naur 符號(hào)集有很多的擴(kuò)展與變種在今天都在使用,包括 擴(kuò)展巴科斯范式(EBNF)和擴(kuò)充巴克斯范式(ABNF).
一個(gè) BNF 規(guī)范是按下面的形式編寫的一套規(guī)則:
<symbol> ::= __expression__
式子左邊通常是一個(gè)非終止符,跟著一個(gè) ::=
符號(hào),代表著“可被換為”。式子右邊 __expression__
由一或多個(gè)符號(hào)序列組成,這些符號(hào)序列被用來推導(dǎo)左側(cè)符號(hào)的意義。
BNF 規(guī)范從根本上說,“無論左側(cè)式子是什么,也無論右側(cè)式子是什么,左側(cè)的式子都能被右側(cè)的式子替換”。
非終止符與終止符
非終止符是指能在之后被替換或被分解的符號(hào)。在 BNF 中,非終止符通常都在尖角括號(hào)中,<
與 >
。在下面的例子中,<integet>
和 <digit>
是非終止符。
<integer> ::= <digit> | <digit><integer>
終止符表明這個(gè)值不能被替換或者分解。在下面的例子中,所有的數(shù)值都是終止符。
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
CSS 屬性值語法
盡管 W3C CSS 屬性值語法是基于 BNF 的概念,它們也有一些不同。像 BNF 的是,它起始于一個(gè)非終止符。不像 BNF 的是,它還描述了用在表達(dá)式中作為“成分值(component values)”的符號(hào)。
在下面的例子中,<line-width>
是非終止符,而 <length>
,thin
,medium
和 thick
是成分值。
<line-width> = <length> | thin | medium | thick
成分值
有四種成分值:關(guān)鍵字、基本數(shù)據(jù)類型、屬性數(shù)據(jù)類型與非數(shù)據(jù)數(shù)據(jù)類型。
1. 關(guān)鍵字值
關(guān)鍵字值不被引號(hào)或尖角括號(hào)包圍。它們可直接作為屬性值。因?yàn)樗鼈儾荒茉俦淮婊蚍纸?,所以它們是終止符。在下面的例子中,thin
、medium
和 thick
都是關(guān)鍵字值。這意味著它們?cè)?CSS 中直接使用。
<line-width> = <length> | thin | medium | thick
2. 基本數(shù)據(jù)類型
基本數(shù)據(jù)類型定義了一些核心值,如 <length>
與 <color>
。它們是非終止符,因?yàn)樗鼈兛梢员惶鎿Q成真實(shí)的長度或顏色值。在下面的例子中 <color>
是基本數(shù)據(jù)類型。
<'background-color'> = <color>
<color>
可在我們的 CSS 中,通過關(guān)鍵字,擴(kuò)展關(guān)鍵字,RGB、RGBA、HSL、HSLA,或 transparent
關(guān)鍵字,被替換為實(shí)際的顏色值。
.example { background-color: red; }
.example { background-color: honeydew; }
.example { background-color: rgb(50%,50%,50%); }
.example { background-color: rgba(100%,100%,100%,.5); }
.example { background-color: hsl(280,100%,50%); }
.example { background-color: hsla(280,100%,50%,0.5); }
.example { background-color: transparent; }
3. 屬性數(shù)據(jù)類型
屬性數(shù)據(jù)類型定義了屬性實(shí)際的名字,是非終止符。它由包含在尖角括號(hào)中的屬性名(包含引號(hào))定義。在下面的例子中,<'border-width'>
是屬性數(shù)據(jù)類型。
<'border-width'> = <line-width>{1,4}
屬性數(shù)據(jù)類型可作為屬性直接出現(xiàn)在我們的 CSS 文件中。在下面的例子中,border-width
屬性給 .exmplate
類定義了 2px 的邊框。
.example { border-width: 2px; }
4. 非屬性數(shù)據(jù)類型
非屬性數(shù)據(jù)類型并不與屬性分享同一個(gè)名字,是非終止符。然而,它定義了某個(gè)(些)屬性的一些層面。例如,<line-width>
不是個(gè)屬性,但它是一個(gè)定義了各種 <border>
的數(shù)據(jù)類型。
<line-width> = <length> | thin | medium | thick
<'border-width'> = <line-width>{1,4}
成分值組合器(Combinator)
使用下面的五個(gè)方法,成分值能被分配至屬性值組合器:
1. 相鄰值
成分值接連而寫意味著所有這些值都必須按給定的順序出現(xiàn)。在下面的例子中,語法列出了三個(gè)不同的值:value1
, value2
與 value3
。在 CSS 規(guī)則中,這三個(gè)值必須按照正確的順序出現(xiàn)才算合法。
/* Component arrangement: all in given order */
<'property'> = value1 value2 value3
/* Example */
.example { property: value1 value2 value3; }
2. 雙與符號(hào)(&)
分開兩個(gè)或更多成分值的雙與符號(hào)(&&
)意味著,這些值必須出現(xiàn),順序任意。在下面的例子中,語法列出了兩個(gè)值,由雙與符號(hào)分開。下面的 CSS 規(guī)則說明了這兩個(gè)值都得出現(xiàn)但可能是不同的順序。
/* Component arrangement: all, in any order */
<'property'> = value1 && value2
/* Examples */
.example { property: value1 value2; }
.example { property: value2 value1; }
3. 單管道符號(hào)
分開兩個(gè)或更多成分值的單管道符號(hào)(|
)意味著,這些值中只需一個(gè)值出現(xiàn)。在下面的例子中,語法列出了三個(gè)值,由單管道符號(hào)分開。在下面的 CSS 規(guī)則中展示了三個(gè)可能選項(xiàng):
/* Component arrangement: one of them must occur */
<'property'> = value1 | value2 | value3
/* Examples */
.example { property: value1; }
.example { property: value2; }
.example { property: value3; }
4. 雙管道符號(hào)
分開兩個(gè)或更多選擇的雙管道符號(hào)(||
)意味著,這些值中一個(gè)或多個(gè)值必須出現(xiàn),順序任意。在下面的例子中,語法列出了三個(gè)值,由雙管道符號(hào)分開。在你寫 CSS 規(guī)則來匹配這個(gè)語法時(shí),有大量可選的選擇 —— 你可以使用一個(gè),兩個(gè)或三個(gè)值,以任意順序。
/* Component arrangement: one or more in any order */
<'property'> = value1 || value2 || value3
/* Examples */
.example { property: value1; }
.example { property: value2; }
.example { property: value3; }
.example { property: value1 value2; }
.example { property: value1 value2 value3; }
...etc
5. 中括號(hào)
包住了兩個(gè)或更多選擇的中括號(hào)([ ]
)意味著其中的成分值屬于一個(gè)單獨(dú)的組。在下面的例子中,語法列出了三個(gè)值,但其中兩個(gè)在中括號(hào)中,所以它們屬于一個(gè)組。所以在 CSS 規(guī)則中有兩種選擇:value1
與 value3
或 value2
與 value3
。
/* Component arrangement: a single grouping */
<'property'> = [ value1 | value2 ] value3
/* Examples */
.example { property: value1 value3; }
.example { property: value2 value3; }
成分值累乘器(Multipliers)
使用下列 8 個(gè)方法之一,成分值也可被重用:
1. ?
問號(hào)(?
)表明其之前的類型,關(guān)鍵字或者組,是可選的且出現(xiàn)零次或一次。在下面的例子中,第二個(gè)成分值與一個(gè)逗號(hào)一起放在了中括號(hào)里。放置其后的問號(hào)意味著,value1
必須出現(xiàn),但我們也可使用 value1
和 value2
,以逗號(hào)分隔。
/* Component multiplier: zero or one time */
<'property'> = value1 [, value2 ]?
/* Examples */
.example { property: value1; }
.example { property: value1, value2; }
2. *
星號(hào)(*
)表明其之前的類型,關(guān)鍵字或者組出現(xiàn)零次或更多次。在下面的例子中,第二個(gè)成分值與一個(gè)逗號(hào)一起放在了中括號(hào)里。放置其后的星號(hào)意味著,value1
必須出現(xiàn),但我們也能隨我們想地使用 value2
任意次,每個(gè)成分值以逗號(hào)分隔。
/* Component multiplier: zero or more times */
<'property'> = value1 [, <value2> ]*
/* Examples */
.example { property: value1; }
.example { property: value1, <value2>; }
.example { property: value1, <value2>, <value2>; }
.example { property: value1, <value2>, <value2>, <value2>; }
...etc
3. +
加號(hào)(+
)表明其之前的類型,關(guān)鍵字或者組出現(xiàn)一次或更多次。在下面的例子中,放置于成分值之后的加號(hào)意味著該值必須被使用超過一次 —— 無需逗號(hào)。
/* Component multiplier: one or more times */
<'property'> = <value>+
/* Examples */
.example { property: <value>; }
.example { property: <value> <value>; }
.example { property: <value> <value> <value>; }
...etc
4. {A}
大括號(hào)({A}
)中包含一個(gè)數(shù)字表明其之前的類型,關(guān)鍵字或者組出現(xiàn) A
次。在下面的例子中,value 的兩個(gè)實(shí)例都必須根據(jù)出現(xiàn)才合法。
/* Component multiplier: occurs A times */
<'property'> = <value>{2}
/* Examples */
.example { property: <value> <value> ; }
5. {A,B}
大括號(hào)({A,B}
)中包含由逗號(hào)分開的兩個(gè)數(shù)字表明其之前的類型,關(guān)鍵字或者組出現(xiàn)至少 A
次,至少 B
次。在下面的例子中,最少一個(gè)、最多三個(gè)值肯能被用來定義該屬性。這些成分值不以逗號(hào)分離。
/* Component multiplier: at least A and at most B */
<'property'> = <value>{1,3}
/* Examples */
.example { property: <value>; }
.example { property: <value> <value>; }
.example { property: <value> <value> <value>; }
6. {A,}
在 {A,}
中 B
被省去了,這意味著至少有 A
次重復(fù),而沒有上限。在下面的例子中,至少需要使用一個(gè)成分值,但也可以額外使用任意數(shù)量的成分值值。這些成分值不以逗號(hào)分離。
/* Component multiplier: at least A, with no upper limit */
<'property'> = <value>{1,}
/* Examples */
.example { property: <value>; }
.example { property: <value> <value>; }
.example { property: <value> <value> <value> ; }
...etc
7. #
井號(hào)(#
)表明其之前的類型,關(guān)鍵字或者組出現(xiàn)一次或多次。在下面的例子中,一個(gè)或多個(gè)成分值可能被使用,這些成分值以逗號(hào)分離。
/* Component multiplier: one or more, separated by commas */
<'property'> = <value>#
/* Examples */
.example { property: <value>; }
.example { property: <value>, <value>; }
.example { property: <value>, <value>, <value>; }
...etc
8. !
一個(gè)組后的感嘆號(hào)(!
)意味著該組是必須的且產(chǎn)生至少一個(gè)值。在下面的例子中,value1
是必須的,以及一個(gè)來自與由 value2
與 value3
組成的組的值。該屬性只有兩個(gè)屬性值;它們是,value1
與 value2
或 value1
與 value3
。
/* Component multiplier: required group, at least one value */
<'property'> = value1 [ value2 | value3 ]!
/* Examples */
.example { property: value1 value2; }
.example { property: value1 value3; }
一個(gè)例子:<'text-shadow'>
語法
讓我們把 <'text-shadow'>
當(dāng)作例子觀察一番。這是它在規(guī)范里的定義:
<'text-shadow'> = none | [ <length>{2,3} && <color>? ]#
我們可以拆分這些符號(hào):
|
表明我們可以使用關(guān)鍵字none
或者一個(gè)組#
表明我們可以使用這個(gè)組一次或多次,以逗號(hào)分割- 在組中,
{2,3}
表明我們可以使用 2 或 3 個(gè)長度值 &&
意味著我們必須包括所有值,但順序可以任意- 有點(diǎn)棘手的是,
<color>
后有一個(gè)?
,這意味著其可能出現(xiàn)零次或一次。
用簡單的話講,這也可以被寫成:
指明了 none 或 一個(gè)或多個(gè)由逗號(hào)分離的組,其中包含了二到三個(gè)長度值與一個(gè)可選的顏色值。長度值與可選的顏色值可以以任意順序編寫。
這意味著我們能夠以很多不同的方式來寫 text-shadow
屬性的值。例如,可以設(shè)置其為 none
:
.example { text-shadow: none; }
我們也可以只寫兩個(gè)長度值,這意味著我們將設(shè)置陰影水平與豎直方向的便宜,但不會(huì)有模糊半徑或者顏色值。
因?yàn)闆]有定義模糊半徑,將會(huì)使用初始值 0
;所以,該陰影的邊緣會(huì)很鋒利。由于沒有定義顏色,所以陰影將使用文本的顏色。
.example { text-shadow: 10px 10px; }
如果我們使用了三個(gè)長度值,我們將會(huì)同時(shí)定義陰影的水平與豎直方向的偏移和模糊半徑。
.example { text-shadow: 10px 10px 10px; }
我們也可以加入顏色,且顏色可以出現(xiàn)在 2 或 3 個(gè)長度值的前面或后面。在下面的例子中,red 值可以放在任一長度值的后面。
.example { text-shadow: 10px 10px 10px red; }
.example { text-shadow: red 10px 10px 10px; }
最后,我們也能包含多個(gè)文本陰影,寫作以逗號(hào)分隔的組。陰影效果將從前至后分層應(yīng)用:第一個(gè)陰影在最頂層,其它的層在其后。陰影不能覆蓋在文本上。在下面的例子中,紅色陰影將在綠黃色陰影的頂上。
.example {
text-shadow:
10px 10px red,
-20px -20px 5px lime;
}
結(jié)論
如果你以寫 CSS 為生,了解如何正確地寫合法的 CSS 屬性值很重要。一旦你了解了不同的值是如何被組合或累乘的,CSS 屬性值語法就變得非常容易理解了。然后看 CSS 的規(guī)范與寫合法的 CSS 都會(huì)變得更容易了。
如果像拓展閱讀,看看下列的網(wǎng)站吧:
- “Value Definition Syntax” in “CSS Values and Units Module Level 3”, W3C
- “CSS Reference,” Mozilla Developer Network
- “How to Read W3C Specs,” J. David Eisenberg, A List Apart