:deep() 是 vue 3 中唯一推荐、稳定且被官方文档明确支持的深度穿透语法;/deep/ 和 >>> 已被弃用或存在兼容风险,不建议新项目使用。 scoped 样式默认无法影响子组件,因 vue 编译时仅给当前组件元素添加 data-v-xxx 属性,子组件内部元素无此属性,导致选择器不匹配。:deep() 必须用于 中的选择器链开头或中间,如 :deep(.el-checkbox__inner),不支持空格分隔的后代选择器,且对 v-html 或 teleport 渲染内容无效。

:deep() 是 Vue 3 中唯一推荐、稳定且被官方文档明确支持的深度穿透语法;/deep/ 和 >>> 已被弃用或存在兼容风险,不建议新项目使用。
为什么 scoped 样式默认无法影响子组件
Vue 编译 <style scoped></style> 时,会给所有选择器自动加上属性选择器(如 [data-v-abc123]),但这个属性只加在当前组件的根元素及其直系子元素上。子组件内部的 DOM 元素(比如 el-checkbox__inner)没有该属性,所以 .el-checkbox__inner 这类规则根本匹配不到。
常见错误现象包括:
- 写好样式后刷新页面,子组件外观毫无变化
- 浏览器开发者工具里能看到样式规则被生成,但“Styles”面板中标记为
inactive - 手动给子组件元素添加
data-v-xxx属性后样式突然生效——这反向验证了作用域隔离机制在起作用
正确使用 :deep() 穿透子组件样式
:deep() 不是 CSS 原生语法,而是 Vue SFC 编译器识别的伪类指令,必须配合 <style scoped></style> 使用,且只能出现在选择器链的**中间或开头**,不能用于声明块内部。
实操要点:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 写法必须是
:deep(.child-class),括号内是子组件中真实存在的类名或选择器,不能带空格(如:deep(.a .b)无效) - 如果要影响多层嵌套,可组合使用:例如
:deep(.el-select) :deep(.el-input__inner),但更推荐逐层穿透或直接命中目标元素 - 支持伪类和属性选择器:
:deep(.el-button:hover)、:deep([type="primary"])都合法 - 不要和
v-html内容混用:由v-html渲染的 HTML 不会自动带作用域属性,:deep()对它无效;需改用全局样式或额外加属性
示例:
<style scoped>
:deep(.el-checkbox__inner) {
border-radius: 50%;
}
:deep(.el-button.is-disabled) {
opacity: 0.6;
}
</style>
/deep/ 和 >>> 为什么不该再用
这两个语法是 Vue 2 时代的遗留方案,现在已明确不推荐:
-
/deep/是 Sass/Less 预处理器的 hack 写法,Vue 3 的 Vite 插件(@vue/compiler-sfc)默认不再解析它,部分构建配置下会直接报错或静默失效 -
>>>是 CSS 原生组合器,但仅在部分浏览器(如旧版 Chrome)中支持,现代标准已废弃,且 Webpack/Vite 构建流程中容易被 CSS minifier 删除 - Vue 官方文档自 3.2+ 起只提
:deep(),所有新教程、CLI 模板、TypeScript 类型定义都围绕它设计 - 如果你在老项目中看到
/deep/,迁移成本极低:全局替换/deep/→:deep()即可,无需改逻辑
容易被忽略的边界情况
穿透不是万能的,以下场景仍会失败:
- 子组件自己也用了
<style scoped></style>并定义了同名类——此时子组件的 scoped 样式优先级更高,:deep()只能覆盖非 scoped 或权重更低的规则 - 目标元素是通过
teleport渲染到 body 下的(如弹窗、提示框),它们脱离了父组件 DOM 树,:deep()失效,需改用全局样式或:global() - 动态类名(如
:class="['base', isActived ? 'active' : '']")中拼接出的类,若未在编译期静态出现,:deep()无法识别
最稳妥的做法始终是:先确认子组件渲染后的实际 HTML 结构和类名,再写 :deep(),别凭记忆或文档猜测。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










