根本原因是层叠顺序与选择器权重不足,需通过DevTools「Computed」面板定位真实生效规则,结合:where()降权、container限定作用域、CSS变量重定义或父容器前缀提升特异性来解决。

根本不是“没写对”,而是你的自定义规则在层叠顺序或选择器权重上输给了 Bootstrap —— 即使它出现在 HTML 的 <link> 标签里更后面,也可能因构建工具注入时机、:where() 降权、JS 动态挂载等机制被绕过。
检查 DevTools 里「Computed」面板的真实生效来源
别只盯着 Elements 面板里 class 名有没有加上。点开任意被覆盖的属性(比如 background-color),看「Computed」→「Styles」里哪条规则带删除线、哪条是最终生效的:
- 如果来源是
bootstrap.min.css,说明你自定义 CSS 根本没加载成功(检查 Network 面板状态码是否为 200) - 如果来源是你自己的文件但属性被划掉,说明权重不够:比如你写了
.my-btn(权重 0,1,0,0),而 Bootstrap 用的是.btn.btn-primary:focus(权重 0,2,0,1) - 如果属性生效了但颜色/尺寸不对,可能是 CSS 变量被覆盖了:
--bs-primary在 :root 上被 Bootstrap 后设,你改.btn-primary { background: red }就会被变量值顶掉
JS 动态组件(Modal/Tooltip)样式失效不是 CSS 问题
这类组件默认插入到 document.body,完全脱离你写的容器结构。你在 #app .btn 里写的样式,对 body 下的 <div class="modal"> 无效。
<ul>
<li>必须显式传 <code>container 选项:new bootstrap.Modal(el, { container: '#app' })
:where(.my-ns) .modal 这类降权选择器配合命名空间容器,否则再高的权重也匹配不到 加 class 来兜底——它太宽泛,容易污染全局,且和 Shadow DOM、微前端场景冲突用 :where() 或变量重定义,比硬写选择器更可靠
直接写 .btn.btn-primary.my-submit { background: #2c3e50 } 能赢一次,但每次换主题色都要扫一遍所有按钮;而改源头更省事:
立即学习“前端免费学习笔记(深入)”;
- Sass 场景:在
@import "bootstrap/scss/variables"之前声明$primary: #2c3e50,确保变量带!default标记 - CSS 变量场景:在
bootstrap.min.css后加<style>:root { --bs-primary: #2c3e50; }</style>,注意分号不能漏 - 想局部降权?用
:where(.my-app) .btn替代.my-app .btn,权重恒为 0,0,1,0,和原生.btn拉平,靠加载顺序决胜
真正难处理的从来不是怎么覆盖,而是哪些地方会“意外穿透”:reboot.css 重置了 button 的默认边框,data-bs-toggle 属性选择器权重高得离谱,还有 Vite 的 CSS 注入顺序和浏览器实际解析顺序不一致——这些细节不查 DevTools 的「Computed」和「Specificity」数值,光靠猜永远调不准。


















