::v-deep 是 Vue 3 中唯一官方支持的深度选择器,/deep/ 和 >>> 已废弃;其必须作为伪类出现在选择器链中且仅影响后续部分,挂载到 body 的组件需用全局样式处理。

::v-deep 是 Vue 3 中唯一被官方支持且稳定可用的深度选择器语法,/deep/ 和 >>> 已废弃或受限于预处理器兼容性,直接使用 ::v-deep 可避免构建报错和样式失效。
为什么 /deep/ 在 Vue 3 项目里会报错
Vue 3 的 @vue/compiler-sfc 默认不再识别 /deep/ —— 它不是 CSS 标准,也不是 Vue 3 编译器保留的关键词。在 Vite 或 Vue CLI 5+ 环境下,/deep/ 会被当作非法 CSS 丢弃,导致样式完全不生成。
- 错误现象:
Unknown word(PostCSS 报错)或控制台无任何对应 CSS 输出 - 根本原因:Vue 3 编译流程中移除了对
/deep/的解析逻辑,仅保留::v-deep作为伪类处理 - 例外情况:某些旧版
vue-loader或自定义 PostCSS 插件可能仍“容忍”/deep/,但这属于兼容性残留,不可依赖
::v-deep 的正确写法与作用范围
::v-deep 必须作为伪类出现在选择器链中,且只影响其**之后**的选择器部分;它不会给前面的父选择器加属性标记,也不会改变权重计算方式。
- ✅ 正确:
.parent ::v-deep .child { color: red; }→ 编译后为.parent[data-v-xxx] .child - ❌ 错误:
::v-deep .parent .child→::v-deep前置无效,会被忽略 - ⚠️ 注意:
::v-deep后不能跟 ID 或属性选择器(如::v-deep #id或::v-deep [disabled]),部分构建工具会静默丢弃 - 嵌套写法(Sass/Less):
.parent { ::v-deep .child { color: red; } },必须顶格写伪类,缩进无效
遇到弹窗、Tooltip 等挂载到 body 的组件怎么办
像 el-dialog、ant-modal、van-popup 这类组件,渲染节点脱离当前组件 DOM 树(挂载到 body),::v-deep 无法穿透到它们身上——因为它们根本不在父组件的 data-v-xxx 属性作用域内。
立即学习“前端免费学习笔记(深入)”;
- 现象:写了
::v-deep .el-dialog,但审查元素发现 dialog 节点没有data-v-xxx属性 - 可行方案:用全局样式 + 特定 class,例如在
src/assets/styles/global.scss中写.my-dialog-wrapper .el-dialog { … } - 更安全的做法:给第三方组件传入
class或wrap-classprop,再配合全局样式精准控制 - 不推荐:把整个
<style>去掉scoped,污染风险高,尤其在微前端或多人协作项目中
Scoped 穿透失效时,优先检查这三件事
很多“穿透不了”其实不是语法问题,而是底层机制没被理解清楚。
- 确认子组件根元素是否真的被 scoped 标记:用浏览器 DevTools 查看目标元素是否有
data-v-xxx属性;若没有,说明该组件本身未启用scoped或使用了teleport - 检查 CSS 优先级:即使穿透成功,外部样式也可能被子组件内部更高权重要素覆盖(比如
!important或行内 style),用 DevTools 的 Styles 面板看哪条规则被划掉 - 验证编译输出:打开
node_modules/.vite/deps或构建产物中的 CSS 文件,搜索你写的::v-deep对应的选择器,确认它是否真实存在且结构符合预期
真正麻烦的从来不是写对一个伪类,而是判断「这个样式到底该不该穿透」——有些时候,改子组件的 props 或用插槽替代硬穿透,反而更可持续。


















