[css]继承关系(一)
一、概述
一个元素最终只有一个css属性对其生效,除了多处指定属性这种情况,还有一种就是元素会继承祖元素的属性,这是一个不简单,也不复杂的问题。
二、继承
一个元素如果本身没有被指定css属性,那么它就会继承父元素的属性,继承是链式的,元素会向上查找,直到遇到指定样式的祖元素,并且继承它的属性:
<style> body{ font-family: cursive; } div{ font-family: monospace; } </style> </head> <body> <p>p</p> <div>div</div> <div><span>div->span <font>div->span->font</font></span></div> </body>
- 元素『p』没有指定font-family属性,往上遍历继承了『body』的font-family属性;
- 元素『div』指定了自己的font-family属性,没有再往上遍历;
- 元素『span』没有指定font-family属性,往上遍历继承了『div』的font-family属性;
- 元素『font』没有自己的font-family属性,往上遍历『span』也没有自己的样式,于是继续遍历,最终继承了『div』的font-family属性;
1.通过元素名称来指定的属性会被其本身和本身的子元素继承:
body { font-family: cursive; }
通过指定『body』元素的样式,所有属于『body』的后代元素都会继承这个样式(一些老旧版本浏览器除外)
2.单独指定元素属性可以摆脱继承:
<style> body{ font-family: unset; } div{ font-family: serif; } </style> <body> <div>div</div> </body>
现在『div』拥有了自己的font-family属性,不再继承『body』的font-family属性
3.多重路径指定
先来看看一段声明:
<style> div span font{ font-family: unset; } body div font{ font-family: serif; } span font{ font-family: serif; } font{ font-family: fantasy; } </style> <body> <div><span>div->span<font>div->span->font</font></span></div> </body>
以上所有声明都指向了『font』元素的情况下,究竟最终会是哪个生效?
通常选择器的优先级遵循以下规则:
- 更详细的选择器优先级更高,所以无论是『body font』还是『span font』都比『font』的优先级更高,同理『body div font』比『span font』优先级更高;
- 同详细的选择器,最后的一个声明会覆盖上面的声明,如同上述例子中,『div span font』与『body div font』中,后者的优先级是最高的,它覆盖了前者;
三、选择器的优先级
css中有3种元素选择器,2种元素指明后缀,如果声明被重叠,那么优先级更高的选择器会覆盖优先级别更低的声明,这也是影响元素样式继承的一个因素;
类型 | 优先级(数字越大优先级越高) | 示例 |
派生选择器 | 1 |
div{...} ul li{...} h1 > strong {...}
li + li {...} |
类选择器 | 2 |
.foo{...} |
类指明后缀 | 2 |
div.foo{...} |
属性指明后缀 | 2 |
div[title="1"]{...} |
id选择器 | 3 |
#bar{...} |
1.元素选择器
举个例子:
<style> .c-2 .c-3{ font-family: serif; } span .c-3{ font-family: serif; } </style> </head> <body> <div class="c-1"><span class="c-2">div->span <font class="c-3">div->span->font</font></span></div> </body>
示例中,尽管『span .c-3』的路径跟『.c-2 .c-3』一样详细并且在『.c-2 .c-3』的下面,但是由于类选择器的优先级比派生选择器的优先级更高,所以『.c-2 .c-3』是最终生效的样式。
同理,如果给示例增加『.c-1 .c-2 .c-3』和『.c-1 span .c-3』两个声明,最终生效的也只会是『.c-1 .c-2 .c-3』。
2.元素指明后缀
给一个选择器加上一个指明后缀,的继承优先级,等价这个选择器后面接一个类选择器:
<style> font[title="1"]{ font-family: serif; } span font{ font-family: serif; } </style> <body> <div title="1" class="c-1" id="i_1"><span class="c-2">div->span<font class="c-3 c-3-1" id="i_1" title="1">div->span->font</font></span></div> </body>
所以上述例子『font[title="1"]』的优先级是比『span font』要高的;
根据以上规则,同路径长度同级的声明,后面的声明会覆盖前面的声明:
<style> .c-2 .c-3{ font-family: serif; } .c-3[title="1"]{ font-family: serif; }
.c-3.c-3-1{
font-family: serif;
} </style> <body> <div title="1" class="c-1" id="i_1"><span class="c-2">div->span<font class="c-3 c-3-1" id="i_1" title="1">div->span->font</font></span></div> </body>
示例中『.c-2 .c-3』和『.c-3[title="1"]』和『.c-3.c-3-1』是等价的,所以最终生效取决于谁声明在最后,这里是『.c-3.c-3-1』;
总结
每一个选择器类编都有它自己的优先级等级,它们不会被具有较低优先级的选择器覆盖。例如,权重为一百万的类选择器不会覆盖权重为一的 ID 选择器。评估优先级的最佳方法是对不同的优先级等级单独进行评分,并从最高的等级开始,必要时再计算低优先级等级的权重。即,仅当某一列的优先级权重相同时,你才需要评估下一列;否则,你可以直接忽略低等级的选择器,因为它们无法覆盖高优先级等级的选择器。
例如这个例子:
<div id="i_1" class="s-1"> <span id="i_2" class="s-2"> hahaha. </span> </div>
以下这个css中,<.s-1 #i_2>会覆盖<#i_1 .s-2>因为它们被认为是相同的优先级,所以最后一条语句覆盖上面的语句:
<style> #i_1 .s-2{color: red;} .s-1 #i_2{color: sienna;} </style>
但是如果把<.s-1 #i_2>改写成<#i_2>,则<#i_1 .s-2>生效,因为<#i_1 .s-2>优先级比<#i_2>高:
<style> #i_1 .s-2{color: red;} #i_2{color: sienna;} </style>
用表格来统筹它们的优先级是如何比较的:
选择器 | ID | 类 | 元素 | 优先级 |
#i_1 .s-2 | 1 | 1 | 0 | 1-1-0 |
.s-1 #i_2 | 1 | 1 | 0 | 1-1-0 |
#i_2 | 1 | 0 | 0 | 1-0-0 |