内联样式优先级最高(1000),其次ID选择器(100)、类名/属性/伪类(10)、元素选择器(1);特异性决定覆盖关系,!important仅单声明生效且破坏可维护性。

内联样式、ID 选择器、类名,谁赢?
内联样式(style 属性)优先级最高,其次是 ID 选择器(#header),再是类名/属性/伪类(.btn、[type="submit"]、:hover),最后是元素选择器(div、p)。这个顺序不是凭感觉,而是由「特异性(specificity)」数值决定的,计算规则是:内联样式 = 1000,每个 ID = 100,每个类/属性/伪类 = 10,每个元素/伪元素 = 1。
常见误区是以为写在后面的样式一定生效——其实只要前面某条规则特异性更高,哪怕它在 CSS 文件靠前,也会覆盖后面低特异性的声明。
-
!important会绕过特异性计算,但只对单个声明生效,且会破坏可维护性,不建议用于常规覆盖 - 两个规则特异性相同时,后定义的生效(即层叠顺序)
- 使用
devtools的「Computed」面板可直接看到每条样式的特异性值和是否被覆盖
继承属性为什么有时不生效?
像 color、font-family、line-height 这类属性默认继承,但继承只发生在「未显式设置值」时。一旦子元素自身有任意来源(内联、CSS 规则、浏览器默认)设定了该属性,继承就中断了。
例如:body { color: #333; } 能让 p 继承颜色;但如果某个 p 上写了 color: inherit; 或 color: initial;,行为就不同了:
立即学习“前端免费学习笔记(深入)”;
body { color: #333; }
p.special { color: initial; } /* 重置为浏览器默认色(通常是黑色),不是继承 body 的 #333 */-
inherit强制继承父级计算值,哪怕父级本身也是继承来的 -
unset对继承属性等价于inherit,对非继承属性等价于initial -
all: unset会清空所有继承行为,慎用
如何安全地覆盖第三方库样式(如 Bootstrap)?
直接加 !important 是最省事但最危险的做法——它会让后续任何调整都必须用更强力的 !important,形成恶性循环。更可持续的方式是提升你自己的选择器特异性,或利用作用域隔离。
- 用更具体的选择器:把
.btn改成.my-app .btn或body.my-theme .btn - 在构建流程中,把自定义 CSS 放在第三方 CSS 之后加载(确保层叠顺序)
- 现代方案:用 CSS Modules 或
(Vue)限制样式作用域,避免全局污染 - 若必须用
!important,仅限极少数无法通过结构控制的场景(如覆盖 inline style 的第三方组件)
display: none 和 visibility: hidden 谁能被继承?
visibility 是继承属性,display 不是。这意味着:parent { visibility: hidden; } 会让所有后代不可见(即使子元素设 visibility: visible,也无效,除非父级是 collapse 表格相关);而 parent { display: none; } 会直接移除整个盒模型,后代根本不会渲染,自然谈不上继承。
这个区别直接影响调试逻辑——如果一个元素“消失了”,先检查它是被 display: none 移除了,还是被 visibility: hidden 隐藏了但占位还在。
-
display: none触发重排(reflow),visibility: hidden只触发重绘(repaint) -
visibility: hidden的子元素可通过visibility: visible单独显示(仅当父级不是hidden) - 屏幕阅读器对两者处理不同:
display: none完全忽略内容,visibility: hidden仍可能读出
实际覆盖样式时,最容易被忽略的是「父级 display 状态导致子元素根本没机会应用样式」,以及「以为设置了 color 就一定生效,却忘了祖先用了 visibility: hidden 把整块内容压住了」。










