彻底搞懂 CSS 生效规则

1,796 阅读6分钟

前言

这段时间正在进行面试官培训,把很久以前整理的前端知识体系拿出来过了一遍,感觉又有了新的收获。这次就分享一下CSS代码生效的规则。

概念

先直接上 MDN 对优先级的定义:

浏览器通过优先级来判断哪一些属性值与一个元素最为相关,从而在该元素上应用这些属性值。优先级是基于不同种类选择器组成的匹配规则。

一个 Dom 元素在浏览器的页面最终展现的样式通常是多段 CSS 代码组合后的结果,如下图,多段 CSS 代码都设置了divfont-size属性,而最后是优先级最高的代码生效,展现出我们在页面上实际看到的效果。 console.png

内联样式和外联样式

内联样式

<div style="color: red;">
  测试
</div>

外联样式

<div>
测试
</div>

<style>
div {
  color: blue;
}
</style>

如上所示,将 CSS 代码写在html标签的style属性中,就属于内联样式。

将 CSS 代码写在<style></style>标签中,或者是写在用<link/> 标签引入的.css 文件中,都属于外联样式。

CSS 样式生效的优先级,内联样式高于外联样式,也就是说如果在内联样式和外联样式中对同一个 dom 元素的某个属性进行设置,那内联样式会覆盖外联样式。

!important

有一个唯一例外的属性,那就是!important

div {
  color: red !important;
}

给任何 css 属性后面添加!important可以使该属性的优先级提升至最大,即使外联样式也可以覆盖内联样式。在前端的各种最佳实践中,一般是禁止使用!important的,即使是迫不得已要使用,也坚决不在内联样式中使用,否则就会导致该属性永远不会被覆盖。

外联样式(CSS 选择器)

前端开发写的 CSS 代码大部分还是外联样式,前端同学也应该都知道,CSS 选择器的优先级如下

ID 选择器 > 类选择器(伪类选择器、属性选择器) > 标签选择器(伪元素) > 通用元素选择器(*)

id 选择器

#app {
  color: red;
}

类选择器

.app {
  color: red;
}

标签选择器

div {
  color: red;
}

通用元素选择器

* {
  color red;
}

优先级不同

下面来讲一下选择器的优先级的比较规则,最基础的规则就是按照上面的选择器优先级,从左往右比较,前一级相等才能向后比较。

<div class="header" id="nav">测试</div>

<style>
#nav {
  color: red;
}

.header {
 colro: blue;
}
</style>

从这个例子来看,最后显示在页面上的文本是红色,从左向右比较,ID 选择器优先级高。

<div class="header">测试</div>

<style>
div.header {
  color: red;
}

.header {
 colro: blue;
}
</style>

这个例子,最后显示在页面上的文本还是红色,从左往右比较,这两段 css 代码都有类选择器,所以继续向右比较,拥有标签选择器的代码生效。

优先级相同

如果两段 css 代码的优先级相同,那么它们在引入 html 的时候,谁定义的越靠后,谁生效

<div class="nav header">测试</div>

<style>
.header {
  color: red;
}

.nav {
 colro: blue;
}
</style>

这个例子中,文本显示蓝色。

多个低优先级的选择器能覆盖高优先级的选择器吗?

从上述的规则来看,应该以高优先级的选择器为准,但是各个浏览器对 CSS 规则对实现并不一样,在低版本的 FireFox中,256 个低优先级选择器是可以覆盖高优先级的选择器的, 具体原理是所有的类名(classes)都是以8字节字符串存储的。8字节所能h存储的最大值就是255. 当同时出现256个class, 就会越过其边缘,溢出到id区域。截止到现在,只有 IE 浏览器还会出现这种情况。

具体的实验可以看张鑫旭的这篇博客www.zhangxinxu.com/wordpress/2…

CSS属性的继承

通常写CSS代码的时候,会有这样的场景

<div class="container">
  <span>文本</span>
  <span>文本</span>
  <span>文本</span>
  <span>文本</span>
</div>

当我们给父级的div设置color或者font-size的时候,div内部的的span标签内的文本,也会获得相应的样式,这就是CSS的样式继承。并不是所有的CSS属性都可以被继承,下面是我们最常用的的可继承的CSS属性

1.字体系列属性
font:组合字体
font-family:规定元素的字体系列
font-weight:设置字体的粗细
font-size:设置字体的尺寸
font-style:定义字体的风格
font-variant:偏大或偏小的字体
2.文本系列属性
text-indent:文本缩进
text-align:文本水平对刘
line-height:行高
word-spacing:增加或减少单词间的空白
letter-spacing:增加或减少字符间的空白
text-transform:控制文本大小写
direction:规定文本的书写方向
color:文本颜色
3.元素可见性
visibility
4.表格布局属性
caption-side定位表格标题位置
border-collapse合并表格边框
border-spacing设置相邻单元格的边框间的距离
empty-cells单元格的边框的出现与消失
table-layout表格的宽度由什么决定<automatic.fixed.inherit>
5.列表布局属性
list-style-type文字前面的小点点样式
list-style-position小点点位置
list-style以上的属性可通过这属性集合
6.引用
quotes设置嵌套引用的引号类型
7.光标属性
cursor:箭头可以变成需要的形状

继承自父级元素的属性的优先级是多少?

这里又会产生一个问题,如果子元素继承了父元素高优先级的样式,会覆盖本身低优先级的样式吗?看下面这个例子

<div id="parent">
 <span class="child">文本</span>
</div>

<style>
 #parent {
   color: red;
 }
 .child {
   color: blue;
 }
</style>

上述这个结构,浏览器实际的结果,文本会表现为blue的颜色,这就又引出了一条规则。

从父级或者更高的祖先那里继承的样式,优先级永远比不上直接设置在本身的样式

CSS优先级的使用场景

现在的前端开发,组件化已经成为标准规范,当我们在自己的代码中调用其他的组件,无论是自己封装的还是三方的组件库。如果对组件内部的样式要进行调整,而组件本身又没有提供对应的方法时,使用高优先级的CSS代码进行覆盖是常用的方式。

前端最常见的样式问题,如果不懂CSS优先级的知识,解决起来可能是非常痛苦的,熟悉CSS优先级可以让开发人员更快的定位并解决问题。

以上就是这次分享的内容。