根本原因是自定义规则未参与层叠竞争;需确认HTML中<link>实际顺序(bootstrap.min.css必须在custom.css或Element Plus等之前)、检查Network面板是否200、用组合选择器提权、限定父容器作用域、处理JS动态挂载节点脱离样式范围问题。

Bootstrap 的 CSS 样式与自定义组件(如 Element Plus、Tippy.js、自研 Web Component)冲突,不是你写错了样式,而是你的规则根本没参与层叠竞争——浏览器压根没选中它。
检查实际加载顺序和是否真被解析
构建工具(Vite/Webpack)可能把所有 CSS 打包进一个文件并重排顺序,光看 import 顺序没用。必须打开浏览器「查看页面源代码」,确认 <link href="bootstrap.min.css"> 确实在你的 custom.css 或 element-plus/index.css 之前,且没加 async 或 defer。
- Vite 用户重点检查
vite.config.ts中是否启用了css.preprocessorOptions,它可能导致 SCSS 注入早于预期 - Vue 单文件组件里
<style scoped>不会匹配.btn,得用:deep(.el-button)或::v-deep .el-input__inner(Vue 2)穿透作用域 - Network 面板里确认两个 CSS 文件都返回 200,路径真实存在——404 就等于没加载,权重再高也没入场券
用组合选择器提权,别碰 !important
Bootstrap 的 .btn.btn-primary 权重是 0,0,2,0;你只写 .my-btn 是 0,0,1,0,天然输一截。堆 !important 在以下场景会突然失效:style="z-index: 2147483647"(内联)、Dark Reader 插件、Shadow DOM、或 Bootstrap 新增的 [data-bs-theme="dark"] .btn 规则。
- 给元素加语义类:HTML 写
<button class="btn btn-primary my-submit">,CSS 写.btn.my-submit { background-color: #d32f2f; },权重拉到平级,不破坏基础样式 - 用父容器限定更安全:
.dashboard .el-input__inner(0,0,3,0),比单类.el-input__inner更可靠 - 属性选择器抗干扰强:
button[type="submit"].btn比.btn更难被 DOM 变动影响
JS 动态插入的 DOM 节点容易脱离样式作用域
Modal、Tooltip、Dropdown 默认挂载到 document.body,而你的自定义样式作用域(比如 .my-bs 容器)在 #app 内——节点一出来就脱离容器,选择器匹配失败是静默的,连报错都没有。
立即学习“前端免费学习笔记(深入)”;
- Tippy.js 用
appendTo: document.body+ 给 body 加class="my-bs",让.my-bs .tippy-box生效 - Element Plus 的
el-dialog需设append-to-body为false,再手动包裹进<div class="my-bs"></div> - 自定义 Web Component 用
adoptedStyleSheets注入已加载的 BootstrapCSSStyleSheet实例,而不是复制 CSS 或写:host .btn
优先改 CSS 变量,而不是硬覆盖类
Bootstrap 5.2+ 的按钮状态、字体、圆角等大量依赖 --bs-* 变量驱动。直接写 .btn-primary { background-color: red; } 会漏掉 :hover、:active,且被变量值反向覆盖。
- 全局换主色:在
:root里重设--bs-primary,一行生效,全状态联动 - 补漏关键组件:单独给
.form-select、.dropdown-menu显式声明font-family: var(--bs-font-sans-serif) - Sass 用户在
@import "bootstrap/scss/bootstrap"前重定义带!default的变量,比如$border-radius: 6px;
真正卡住人的不是“怎么写 CSS”,而是没意识到 JS 组件挂载点和 CSS 作用域必须对齐——Modal 插到 body,你的样式却锁在 #app 里,这问题在 DevTools 里连划掉的样式都看不到。


















