层叠
CSS 本质上就是声明规则,即在各种条件下,我们希望产生特定的效果。浏览器会根据这些规则,判断每个规则应该用在哪里,并使用它们去渲染页面。
对同一个元素应用多个规则时,规则中可能会包含冲突的声明。
<header class="page-header">
<h1 id="page-title" class="title">Wombat Coffee Roasters</h1>
<nav>
<ul id="main-nav" class="nav">
<li><a href="/">Home</a></li>
<li><a href="/coffees">Coffees</a></li>
<li><a href="/brewers">Brewers</a></li>
<li><a href="/specials" class="featured">Specials</a></li>
</ul>
</nav>
</header>
h1 {
font-family: serif;
}
#page-title {
font-family: sans-serif;
}
.title {
font-family: monospace;
}
三个规则集尝试给标题设置不同的字体,哪一个会生效呢?浏览器为了解决这个问题会遵循一系列规则,因此最终的效果可以预测,规则决定了第二个声明(即ID选择器)生效,因此标题采用sans-serif字体。
层叠指的就是这一系列规则。它决定了如何解决冲突,是CSS语言的基础。
当声明冲突时,层叠会依据三种条件解决冲突。
- (1) 样式表的来源:样式是从哪里来的,包括你的样式和浏览器默认样式等。
- (2) 选择器优先级:哪些选择器比另一些选择器更重要。
- (3) 源码顺序:样式在样式表里的声明顺序。
样式表的来源
你的样式表属于作者样式表,除此之外还有用户代理样式表,即浏览器默认样式。用户代理样式表优先级低,你的样式会覆盖它们。
有些浏览器允许用户定义一个用户样式表。这是第三种来源,它的优先级介于用户代理样式表和作者样式表之间。用户样式表很少见,并且不受网站作者控制。
用户代理样式
浏览器应用了用户代理样式后才会应用你的样式表,即作者样式表。你指定的声明会覆盖用户代理样式表里的样式。
用户代理样式表设置了用户普遍需要的样式,不会做一些完全超出预期的事情。当你不喜欢默认样式时,可以在自己的样式表里设置别的值。
<header class="page-header">
<h1 id="page-title" class="title">Wombat Coffee Roasters</h1>
<nav>
<ul id="main-nav" class="nav">
<li><a href="/">Home</a></li>
<li><a href="/coffees">Coffees</a></li>
<li><a href="/brewers">Brewers</a></li>
<li><a href="/specials" class="featured">Specials</a></li>
</ul>
</nav>
</header>
h1 {
color: #2f4f4f;
margin-bottom: 10px;
}
#main-nav {
margin-top: 10px;
list-style: none;
padding-left: 0;
}
#main-nav li {
display: inline-block;
}
#main-nav a {
color: white;
background-color: #13a4a4;
padding: 5px;
border-radius: 2px;
text-decoration: none;
}
! important声明
样式来源规则有一个例外:标记为重要(important)的声明。
在声明的后面、分号的前面加上!important
,该声明就会被标记为重要的声明。如:color: red ! important
。
标记了!important
的声明会被当作更高优先级的来源。
理解优先级
如果无法用来源解决冲突声明,浏览器会尝试检查它们的优先级。浏览器将优先级分为两部分:HTML的行内样式和选择器的样式。
行内样式
如果用HTML的 style 属性写样式,这个声明只会作用于当前元素。实际上行内元素属于“带作用域的”声明,它会覆盖任何来自样式表(.css)或者 <style> 标签的样式。行内样式没有选择器,因为它们直接作用于所在的元素。
为了在样式表里覆盖行内声明,需要为声明添加!important
,这样能将它提升到一个更高优先级的来源。但如果行内样式也被标记,就无法覆盖它了。最好不要在行内样式用!important
。
选择器优先级
不同类型的选择器有不同的优先级。如果选择器的ID数量更多,则它会胜出(即它更明确)。如果ID数量一致,那么拥有最多类的选择器胜出。如果以上两次比较都一致,那么拥有最多标签名的选择器胜出。
伪类选择器(如:hover)和属性选择器(如[type=“input”])与一个类选择器的优先级相同。通用选择器(*)和组合器(>、+、~)对优先级没有影响。
优先级标记
一个常用的表示优先级的方式是用数值形式来标记,通常用逗号隔开每个数。比如,“1,2,2”表示选择器由1个ID、2个类、2个标签组成。优先级最高的ID列为第一位,紧接着是类,最后是标签。
比如:选择器#page-header #page-title有2个ID,没有类,也没有标签,它的优先级可以用“2,0,0”表示。
有时,人们还会用4个数的标记,其中将最重要的位置用0或1来表示,代表一个声明是否是用行内样式添加的。此时,行内样式的优先级为“1,0,0,0”。
关于优先级的思考
优先级容易发展为一种“军备竞赛”。在大型项目中这一点尤为突出。通常最好让优先级尽可能低,这样当需要覆盖一些样式时,才能有选择空间。
源码顺序
如果两个声明的来源和优先级相同,其中一个声明在样式表中出现较晚,或者位于页面较晚引入的样式表中,则该声明胜出。
面对一个样式问题时,我经常分两个步骤来解决它。首先确定哪些声明可以实现效果。其次,思考可以用哪些选择器结构,然后选择最符合需求的那个。
继承
如果一个元素的某个属性没有层叠值,则可能会继承某个祖先元素的值。
但不是所有的属性都能被继承。默认情况下,只有特定的一些属性能被继承,通常是我们希望被继承的那些。它们主要是跟文本相关的属性:color、font、font-family、font-size、font-weight、font-variant、font-style、line-height、letter-spacing、text-align、text-indent、text-transform、white-space以及word-spacing。
还有一些其他的属性也可以被继承,比如列表属性:list-style、list-style-type、list-style-position以及list-style-image。表格的边框属性border-collapse和border-spacing也能被继承。
继承属性会顺序传递给后代元素,直到它被层叠值覆盖。
使用开发者工具能够看到哪些元素应用了哪些样式规则,以及为什么应用这些规则。层叠和继承都是抽象的概念,使用开发者工具是最好的追踪方式。在一个页面元素上点击鼠标右键,选择弹出菜单上的检查元素,就能打开开发者工具,示例如下所示。
特殊值
使用inherit关键字
有时,我们想用继承代替一个层叠值。这时候可以用inherit关键字。可以用它来覆盖另一个值,这样该元素就会继承其父元素的值。
还可以使用inherit关键字强制继承一个通常不会被继承的属性,比如边框和内边距。
使用initial关键字
有时,你需要撤销作用于某个元素的样式。这可以用initial关键字来实现。每一个CSS属性都有初始(默认)值。如果将initial值赋给某个属性,那么就会有效地将其重置为默认值,这种操作相当于硬复位了该值。
这么做的好处是不需要思考太多。如果想删除一个元素的边框,设置border:initial即可。如果想让一个元素恢复到默认宽度,设置width: initial即可。
注意:initial重置为属性的初始值,而不是元素的初始值。 |
---|
简写属性
简写属性是用于同时给多个属性赋值的属性。比如font是一个简写属性,可以用于设置多种字体属性。它指定了font-style、font-weight、font-size、font-height以及font-family。
简写属性会默默覆盖其他样式
大多数简写属性可以省略一些值,只指定我们关注的值。但是要知道,这样做仍然会设置省略的值,即它们会被隐式地设置为初始值。这会默默覆盖在其他地方定义的样式。
理解简写值的顺序
简写属性会尽量包容指定的属性值的顺序。可以设置border: 1px solid black或者border: black 1px solid,两者都会生效。这是因为浏览器知道宽度、颜色、边框样式分别对应什么类型的值。
但是有很多属性的值很模糊。在这种情况下,值的顺序很关键。
上、右、下、左
当遇到像margin、padding这样的属性,还有为元素的四条边分别指定值的边框属性时。这些属性的值是按顺时针方向,从上边开始的。
这种模式下的属性值还可以缩写。如果声明结束时四个属性值还剩一个没指定,没有指定的一边会取其对边的值。指定三个值时,左边和右边都会使用第二个值。指定两个值时,上边和下边会使用第一个值。如果只指定一个值,那么四个方向都会使用这个值。
水平、垂直
还有一些属性只支持最多指定两个值,这些属性包括background-position、box-shadow、text-shadow(虽然严格来讲它们并不是简写属性)。
这些属性值的顺序跟padding这种四值属性的顺序刚好相反。比如,padding: 1em 2em先指定了垂直方向的上/下属性值,然后才是水平方向的右/左属性值,而background-position: 25% 75%则先指定水平方向的右/左属性值,然后才是垂直方向的上/下属性值。
这两个值代表了一个笛卡儿网格。笛卡儿网格的测量值一般是按照x, y(水平,垂直)的顺序来的。第一个值指定了水平方向的偏移量,第二个值指定了垂直方向的偏移量。