根本原因是::v-deep在Vue 2+Sass中必须嵌套在父选择器内(如.form-item{::v-deep .el-input__inner{...}}),否则vue-loader无法注入data-v-xxx锚点,导致编译后选择器不匹配目标DOM。

根本原因不是 Sass 本身,而是 ::v-deep 在 Vue 2 + Sass 环境下被错误编译或未正确嵌套,导致生成的选择器不匹配目标 DOM。
Vue 2 中 ::v-deep 在 Sass 里必须写在嵌套层级内部
很多人把 ::v-deep 当成普通 CSS 选择器,直接写在顶层,比如:
.form-item ::v-deep .el-input__inner { border: 2px solid blue; }
这在 Vue 2 的 vue-loader + sass 组合下大概率失效——因为 vue-loader 要求穿透语法必须出现在 scoped 样式块的“嵌套结构中”,否则不会将 data-v-xxx 属性注入到编译结果里。
正确写法是把它作为嵌套子选择器的一部分:
立即学习“前端免费学习笔记(深入)”;
.form-item {
::v-deep .el-input__inner {
border: 2px solid blue;
}
}
- 必须用大括号包裹,不能写成单行链式
-
::v-deep后面必须紧跟一个空格和子选择器(如.el-input__inner),不能加逗号或换行断开 - 如果父选择器(如
.form-item)本身没渲染出带data-v-xxx的 DOM,整个穿透规则就失去锚点,直接不生效
dart-sass 已彻底不支持 /deep/ 和 >>>
如果你刚把项目从 node-sass 升级到 dart-sass,而代码里还留着 /deep/ 或 >>,编译会直接报错:SassError: expected selector。
这是因为 dart-sass 是 Sass 官方实现,只认标准 CSS 语法扩展,而 /deep/ 和 >> 是 Vue 自定义的非标准伪类前缀,早被弃用。
- ✅ 唯一兼容 Vue 2 和
dart-sass的写法是::v-deep - ❌
/deep/仅在旧版node-sass+vue-loader@15下侥幸可用,不可依赖 - ❌
>>在 Sass 中会被解析为位移操作符,必然报错;>>>更是非法语法
穿透后样式仍被覆盖?优先级和作用域锚点双失效
即使 ::v-deep 编译成功,浏览器里也看到对应规则,但颜色/边框还是没变——大概率是优先级不够,或者你漏掉了“作用域锚点”。
Vue 的 ::v-deep 不是全局开关,它只是让后面的选择器跳过 data-v-xxx 匹配,但前面的父选择器仍受 scoped 限制。所以:
- 如果写成
::v-deep .el-button(无父选择器),编译后等价于全局.el-button,但此时没有data-v-xxx锚定,极易被 Element UI 自带的高优先级规则干掉 - 务必写成
.my-dialog ::v-deep .el-button,这样最终生成类似.my-dialog[data-v-f3f439] .el-button,既保持作用域边界,又提升权重 - 遇到顽固覆盖,可加一层
!important,但更推荐用更具体的选择器,例如.my-dialog .el-dialog__body ::v-deep .el-button--primary
真正容易被忽略的是:scoped 样式穿透生效的前提,是父组件的根元素必须真实存在且携带 data-v-xxx。如果组件用 v-if 控制显示、或根节点是 <template></template>、或被 keep-alive 缓存后 DOM 重用,都可能导致锚点丢失——这时连 ::v-deep 都救不了。


















