前端难点:Element Plus 样式覆盖 ------ :deep()、CSS 变量与滚动状态类名
摘要 :Element Plus 样式改不动、固定列边框消失?从 CSS 变量、:deep() 到 is-scrolling 类名层级。 专栏 :前端难点实战 · 阅读约 8 分钟 · 难度 :⭐⭐⭐ 实战场景:Vue3 中大型 B 端后台
一、为什么改样式「不生效」?
实际项目对 Element Plus 做了大量定制(全局主题 SCSS、表格精简边框变体)。新手常遇到:
scss
.ep-table td {
border-right: none; /* 写了但没效果 */
}
常见原因:
- Scoped 隔离 --- Vue SFC 的
scoped加了[data-v-xxx],选不到 EP 内部 DOM - 优先级不够 --- EP 自带样式 + 内联 style 更具体
- 类名挂错层级 --- 状态类在子组件根上,不在你的 wrapper 上
- EP 版本前缀 --- 项目配置为
ep-前缀(非默认el-)
二、三种覆盖策略(按推荐顺序)
策略 1:CSS 变量(最干净)
EP 2.x 大量组件支持 CSS Variables:
scss
.ep-table {
--ep-table-header-bg-color: #fafafa;
--ep-table-border-color: #e8e8e8;
--ep-table-row-hover-bg-color: #fafafa;
}
改变量 = 全局换肤,升级 EP 版本时 breakage 最小。
策略 2:deep() 穿透 Scoped
vue
<style scoped lang="scss">
.table-clean {
:deep(td.ep-table__cell) {
border-right: none !important;
}
}
</style>
:deep() 让 scoped 编译后仍能选中子组件内部节点。
策略 3:全局 SCSS + BEM 包装类
项目把 Tabs、Dialog、Checkbox 等放在 styles/element/index.scss,业务组件只加 class:
vue
<tabs v-model="activeTab" class="h-tabs--segment">
三、案例:精简边框表格的固定列边框
设计稿要求:去掉单元格右边框,表头用伪元素做短分隔线,左侧固定列始终有分隔线。
Element Plus 只在特定滚动状态下给固定列加 border-right:
html
<div class="ep-table is-scrolling-middle">
<td class="ep-table-fixed-column--left is-last-column">
错误写法(选不到):
scss
.table-clean.is-scrolling-middle td { ... } /* ❌ is-scrolling 在 .ep-table 上 */
正确写法:
scss
.table-clean {
:deep(.ep-table.is-scrolling-none),
:deep(.ep-table.is-scrolling-left),
:deep(.ep-table.is-scrolling-right),
:deep(.ep-table.is-scrolling-middle) {
td.ep-table-fixed-column--left.is-last-column,
th.ep-table-fixed-column--left.is-last-column {
border-right: 1px solid var(--ep-table-border-color) !important;
}
}
}
难点 :必须在 DevTools 里看清状态类挂在哪一层 DOM,再写选择器。
四、案例:Tabs 封装 自定义下划线
EP 自带 active-bar,设计要宽度跟随文字的指示线。方案:
- CSS 隐藏
.ep-tabs__active-bar - 用 CSS 变量
--tabs-bar-x、--tabs-bar-width - JS(MutationObserver + rAF)同步 active tab 的
offsetLeft/offsetWidth
样式与逻辑分离,避免硬编码 left 像素。
五、:global() 与弹窗 append-to-body
el-dialog 默认 append-to-body,DOM 挂在 body 下,不在组件 scoped 树内:
scss
// Dialog 封装 内
:global(.app-dialog:not(.is-fullscreen) .ep-dialog__body) {
flex: 1;
min-height: 0;
}
或用 popper-class / modal-class / body-class 传入包装类名。
六、调试技巧
- Chrome DevTools → 选中元素 → 看 Styles 面板哪条规则赢
- 搜索 EP 源码或 node_modules 里真实 class(
ep-table__cell) - 临时去掉
scoped验证是否是穿透问题 - 慎用
!important,优先变量 + 层级
七、小结
| 场景 | 推荐 |
|---|---|
| 换色、圆角、间距 | CSS Variables |
| 组件内改 EP 结构 | :deep() + 包装 class |
| Dialog/Teleport 节点 | :global() 或 EP 的 *-class props |
| 表格滚动/固定列 | 查清 is-scrolling-* 挂载层级 |
写在最后
以上难点来自真实 B 端项目工程实践。若对你有帮助,欢迎 点赞、收藏,有问题评论区交流。
发布到掘金时建议:
- 分类:前端
- 标签:前端、Element Plus、Vue.js、SCSS、CSS
- 封面:DevTools 布局截图或代码片段图
- 摘要:复制文首「摘要」段落到编辑器摘要栏
专栏「前端难点实战」:
- 上一篇:《前端难点:Vue3 响应式遇上 Three.js / ECharts ------ 为什么要用 shallowRef?》
- 下一篇:《前端难点:ResizeObserver 在 B 端自适应布局中的正确用法》