先问个非常简单的问题,这个问题的答案,相信大部分Web开发人员都自认为显而易见,但却又多半会答错:CSS属性中的初始值(initial value),就是默认值(default value)吗?
难道不对吗?请往下看。
默认值
默认值(default value)指的是没有显式地为CSS属性声明一个值的情况下,所默认使用的隐式缺省值。
注: 这里所说的默认值,并非各个浏览器自带的CSS默认值,为避免混淆,下面称浏览器默认值为浏览器自带值。
CSS规范中并未显式地明确定义默认值的概念,但根据对CSS规范的理解,可认为其隐式地定义了默认值,如下:
- 对于非继承属性(CSS属性一览表[1]中inherited为no的属性),默认值为初始值initial;
- 对于继承属性(CSS属性一览表中inherited为yes的属性):
- 若不是根元素(根元素是指:root选择器匹配到的元素,在html文档中一般指的是html元素,但也可能不是,以后专文介绍),则默认值为继承值inherit;
- 若是根元素,则默认值为初始值initial。
判断一个属性是不是继承属性,除了查询W3C官网上的CSS属性一览表,还有没有相对快捷的方法呢?
有的,大致上来说:
- 跟文本、声音等与内容相关的属性,比如font、color、text-align、line-height、white-space、speak、voice-family、volume等属性,都是可继承属性;
- 跟框模型、定位等与布局相关的属性,比如background、border、display、float、height、left、overflow、vertical-align、z-index等属性,都是非继承属性。
注意: 在实践中,由于各个浏览器会设定某些常用元素的常用CSS属性的值(即前文所述的浏览器自带值),因此只有在浏览器并没有显式地设定其值,并且其他各级样式(包括元素的style属性所设置的行间样式)也没有显式地设定其值的情况下,才会最终使用上述的默认值。
初始值
在W3C CSS规范的每个CSS属性定义表中,已经给出了属性的初始值(initial value),如下图所示。
初始值对于继承属性和非继承属性[2],有着不同的含义:
- 对于继承属性,初始值只能被用于没有指定值的根元素上;
- 对于非继承属性,初始值可以被用于没有指定值的任意元素上。
在CSS 3中,允许使用initial关键词明确地设定初始值,也就是说,关键词initial代表初始值,不过目前各浏览器对关键词initial的支持情况较差,可通过http://caniuse.com查看具体的支持情况。
继承值
每个CSS属性定义表中,都指出了这个属性是默认继承的("Inherited: Yes"),还是默认不继承的("Inherited: no")(可参看W3C的CSS属性全表Full property table[3])。
继承值(inherit value)决定了当没有为元素的属性手动设置其值时该如何确定其值。
当元素的一个继承属性 没有手动设置其值时,则取父元素相同属性的计算值computed value[4],该值即为继承值。
注意,子元素不直接继承为其父元素所指定的相对数值,而是继承其父元素经过计算之后的数值——计算值,可能是绝对数值,也可能仍然还是相对数值,详见下文对计算值的介绍。
比如,在以下规则中,如果"h1"是"body"元素的子级,则"h1"元素所继承的"text-indent"属性值将为36px,而不是3em,因此最终其值不会是45px:
body {font-size: 12px;text-indent: 3em; /* 计算值为36px */}h1 { font-size: 15px; }
下面的示例中,P元素的子元素继承的"line-height"的值为12px,而不是百分比值(120%):
p {font-size: 10px;line-height: 120%;
}
但文档根元素由于没有父元素,如果在根元素上为某个CSS属性设置了inherit值,则会取该属性在CSS规范中所定义的初始值[5](但如果设置了浏览器自带值,则取浏览器自带值)。
声明值
为每个属性显式地声明的值(或者说设置的值),称之为声明值(declared value),或称之为设置值。
声明值可能是程序员手动显式声明的值(包括内联样式、外部样式、行间样式中所声明的值),也可能是浏览器显式设置的浏览器自带值。
声明值是相对于默认值而言的,如果一个CSS属性在各级样式(包括浏览器自带样式、内联样式、外部样式、行间样式)中都没有显式的声明值,则使用隐式的默认值。
层叠值
层叠值(cascaded value),也译作级联值,指的是对多个来源的各级样式(包括浏览器自带样式、浏览器用户自定义样式、内联样式、外部样式、行间样式)的默认值或声明值进行层层叠加计算后的结果值。
该结果值是参与层叠计算的样式值中符合层叠计算规则的优先级最高的值,要么是某级样式中的一个默认值,要么是某级样式中的一个声明值。
这也就是“CSS层叠样式表”这个名称的来源。
因此,层叠值的计算相当于各级样式优先级的计算,最后以优先级最高的为准。
层叠值的计算,涉及到样式的来源origin、重要性important、特殊性specificity,需遵循CSS层叠规则。
一个元素某个CSS属性的层叠值,在按层叠计算规则计算之后,如果该属性最终有“胜出的”声明值,则该值为层叠值。
层叠计算规则比较复杂,后面将专文进行介绍。
指定值
CSS属性的指定值(specified value)通过以下途径获取:
- 如果当前文档的各级样式层叠后的层叠值不是空值,则该层叠值为指定值。例如:各级样式层叠计算后,color属性的值为green,则green为color属性的指定值;
- 否则,如果层叠值是空值,则以该属性的默认值作为指定值。具体而言:
- 如果该属性为继承属性,并且其所在元素不是文档的根元素,则使用父元素的计算值作为指定值。例如:在一个<div>内部放置一个段落<p>,这个<div>的font属性的计算值为"Arial",而<p>的font属性属于继承属性,那么它的font属性的指定值就会继承为Arial;
- 如果该属性为非继承属性,或是文档根元素的属性,则将CSS规范中针对该属性所定义的初始值initial value作为指定值。
这样,指定值就保证了为每个元素的每个CSS属性都一定指定了一个值。
计算值
一个CSS属性的计算值(computed value)通过以下方式获得:
- 处理特殊的值:inherit、initial、unset和revert;以及
- 进行计算,以达到属性定义表中“计算值Computed Value”所描述的值。
达到属性"计算值"所需的计算,通常涉及到相对计算,也就是将相对比值(如em单位或百分比值)转换成绝对数值的计算过程。
例如,一个元素具有声明值为:font-size: 16px和padding-top: 2em,则padding-top的计算值为32px(字体大小的2倍)。
然而,有些属性的百分比值会转换成百分比的计算值,也就是说,计算后还是百分比值,因此仍然是相对比值,而不是绝对数值,因为这些元素的百分比值是相对于需要布局后才能知道的值,如width、margin-right、text-indent和top等。
另外,line-height属性值如果是不带单位的数字值(这属于相对比值),则该值就是其计算值。
这些计算值中的相对比值会在使用值(used value)确定后再被转换成绝对数值。
计算值通常是为了在继承的准备过程中对属性值尽可能进行绝对化。当然,也只是尽可能而已,如上所述,计算值仍然有可能是相对比值,而不是绝对数值。
注意: 由于历史原因,CSS 2.1之后,计算值不一定是[Window.getComputedStyle()](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/getComputedStyle "Window.getComputedStyle( "Window.getComputedStyle()")") 函数返回的值,所以该函数所返回的值被称之为“解析值”(详见下文解释),而不是“计算值”,虽然有时候返回的值确实就是计算值。
使用值
CSS属性的使用值(used value)是在取得计算值,并完成剩余计算(如果有的话)后的结果值。
使用值一定是绝对数值,这一点与计算值仍然有可能是相对比值是不同的。
相对于下面要提到的实际值(actual value)而言,使用值是文档布局中所使用的理论值。
如果一个属性不适用于某个元素,则该元素没有这个属性的使用值(但其计算值很可能仍然是存在的,只是会被忽略)。比如,flex属性在非flex项目的元素上没有使用值。
计算出CSS属性的使用值,有如下三个步骤:
- 首先,指定值(specified value)来自于各级样式层叠后的层叠值(即选取各级样式里权重最高的规则),继承值(如果是继承属性,且默认值为inherit),或者初始值。
- 然后,按规范计算出计算值,如span指定position属性的值为absolute后,其display属性的值变为block。
- 最后,计算布局(尺寸比如为auto或百分数则换算为像素值),计算结果即为使用值。
这些计算步骤是在内部完成的,JavaScript脚本只能使用Window.getComputedStyle()获得最终计算后的使用值(通过Window.getComputedStyle()获得的值,还有可能是计算值,具体请看下文对解析值resolved value的解释)。
使用值示例
- 没有设置明确的宽度,则宽度的指定值为auto(默认),计算值为auto,使用值为998px (举例而言);
- 设置了明确的宽度为50%,则宽度的指定值为50%,计算值为50%,使用值为447px;
- 设置了明确的宽度为inherit,则宽度的指定值为50%(举例而言),计算值为50%,使用值为221px。
使用值与计算值的区别
CSS 2.0只定义了计算值作为属性计算的最后一步。CSS 2.1引进了定义明显不同的使用值,这样当父元素的计算值为百分比值时,比如上述示例中的宽度值,子元素仍然可以显式地继承该值。
对于不依赖于布局的CSS属性(例如display、font-size、line-height),其计算值与使用值一样,否则就会不一样。
解析值
CSS属性的解析值(resolved value)是Window.getComputedStyle()返回的值。
对于大多数属性,解析值等于其计算值,但对于一些旧属性,比如width、height等,它等于其使用值。
实际值
一个CSS属性的实际值(actual value),是使用值(used value)被使用后的近似值。
例如,浏览器可能只能渲染一个整数像素值的边框,而该整数像素值(实际值)可能是一个小数值(使用值)被强制四舍五入取整之后的近似结果值。
下表为W3C CSS规范[6]上的示例(表中的Winning declaration为层叠计算后最终“胜出的”属性声明值):
参考资料
[1] CSS属性一览表: https://www.w3.org/TR/CSS21/propidx.html
[2] 继承属性和非继承属性: https://developer.mozilla.org/en-US/docs/CSS/inheritance
[3] CSS属性全表: https://www.w3.org/TR/CSS21/propidx.html
[4] 计算值: https://developer.mozilla.org/en-US/docs/CSS/computed_value
[5] 初始值: https://developer.mozilla.org/en-US/docs/CSS/initial_value
[6] W3C CSS 规范: https://www.w3.org/TR/css-cascade-3/#stages-examples