根本原因是CSS选择器权重不足:Bootstrap的.btn.btn-primary权重为0,0,2,0,而单类.btn仅0,0,1,0,即使后加载也因特异性低被忽略;应改用.btn.my-btn提权至平级,或通过父容器限定、CSS变量等无侵入方式解决。

根本不是你写错了,而是浏览器压根没选你的规则——它被 Bootstrap 的同名类“挡”在了外面。
为什么 .btn { background: red } 完全不生效
Bootstrap 的 .btn.btn-primary 权重是 0,0,2,0(两个类),而你的 .btn 只有 0,0,1,0。即使你把它写在 Bootstrap CSS 后面,权重低就输;浏览器不看“谁后加载”,只算“谁更具体”。
- 打开开发者工具 → Elements 面板 → 选中按钮 → 切到 Styles 面板,看
background是否被划掉 - 再点那个被划掉的声明,看来源是不是
bootstrap.min.css - 如果 Computed 面板里显示的
background来自.btn.btn-primary,说明你的单类规则连入场券都没拿到
用 .btn.my-btn 而不是 .my-btn 提权到平级
Bootstrap 本身靠组合类工作,你硬加 ID 或 !important 是对抗,而复用它的结构是协同。给已有 .btn 的元素再加一个自定义类,然后在 CSS 里写 .btn.my-btn,权重立刻升到 0,0,2,0,和 .btn.btn-primary 平起平坐。
- HTML:
<button class="btn btn-primary my-btn">Submit</button> - CSS:
.btn.my-btn { background-color: #d32f2f; }—— 不需要!important,也不污染全局 - 如果要限定范围,加父容器前缀:
.dashboard .btn.my-btn(权重 0,0,3,0),安全又可控
避免 !important 的三个翻车现场
!important 看似快,但会在这些地方突然失效:
立即学习“前端免费学习笔记(深入)”;
- Bootstrap 组件内部用了内联样式(如
style="color: var(--bs-danger);"),内联权重 1000 > 类+!important - 用户装了 Dark Reader 等插件,它用更高权重或 JS 注入样式,直接覆盖你
- Vue/React 的
<style scoped>或 Shadow DOM 会隔离作用域,!important出不去
构建工具里 link 顺序可能被悄悄重排
你以为 import 'bootstrap.css'; import './custom.css'; 就稳了?Vite/Webpack 可能把所有 CSS 打包进一个 index.css,并按依赖图重排顺序。最终生效的,是浏览器里 HTML 源码中 <link> 的实际顺序。
- 打开浏览器「查看页面源代码」,确认
custom.css的<link>确实在bootstrap.min.css之后 - Vite 用户检查
vite.config.ts中是否启用了css.preprocessorOptions,它可能导致注入时机错乱 - CDN 场景下,手动把自定义 CSS 的
<link>放在 Bootstrap<link>下方,且不要加async或defer
真正难处理的从来不是“怎么提权”,而是“提完权之后,要不要为每个新组件都补一层选择器”——所以优先考虑 CSS 变量(如 --bs-border-radius)或编译时命名空间(:where(.my-bs) {}),它们不依赖选择器权重,也更接近问题本质。


















