Vue 中的样式穿透 v-deep、/deep/ 和 >>>

Vue 项目的开发中,很多人都因为想要限制 CSS 样式的作用范围(避免样式污染的问题)去使用 scope 属性。

但是很多的情况下都会去修改分装好的子组件以及UI库中的组件样式,所以经常会用到 样式穿透 这个东西,因为我以前是使用的 Stylus 作为样式预处理器的,所以并没有感觉到什么困惑的地方,但是有很多同学是使用的 Scss 以及 Less 的,对于他们来说什么时候使用 /deep/ 什么时候使用 ::v-deep 是很困扰的。特别是对于一些刚刚进入前端圈的小伙伴们。

正好最近在思否也遇到了很多人来问这样的问题,就像一次性都把相关的疑问都回答了。

💡 我想要书写样式穿透的时候应该怎么办?

Vue2 版本中:

  • 如果你是使用的 Stylus 以及 CSS 那么不用考虑直接使用 CSS 所支持的 >>> 来穿透就可以了。

  • 如果说你使用的是 Less 以及 Sass 的话,那么推荐使用 ::v-deep 来实现样式穿透的效果。

为什么不使用 /deep 呢,因为现在的 Sass 默认安装的是 dart-sass 如果你使用 /deep/ 会提示错误:SassError: expected selector. /deep/,所以直接使用 ::v-deep 预防可能会出现的问题。

并且最好不要直接使用 ::v-deep 等样式穿透来书写,比如说:

<style scoped lang="scss">
::v-deep .className { 
  ... 
}
</style>

这样的话,其实就和你没有添加 scope 的结果是一样的了,并不会只限制在当前组件内。而会污染到全局样式当中。
并且直接使用 /deep/ .className 可能无法通过 loader 的编译。

如果说你使用的是 Vue3 的话,就需要把 ::v-deep 替换成 :deep()

💡 如果是添加到 body 元素上的组件怎么办,比如说 el-dialog 这种弹窗组件。

一般都会提供一个 custom-class 给你使用,可以借助这个来起一个 className 来给它们添加样式,或者可以直接使用 class 来给当前页面中的弹窗元素起一个CSS类名。
然后写在全局就可以了,没有必要通过样式穿穿透来覆写。当然也可以写在 scope 内,因为第一级会被添加上当前组件的 hash 值。来起到限制作用域的要求。


相关阅读

Scoped CSS | Vue Loader
rfcs/0023-scoped-styles-changes.md at master · vuejs/rfcs
vue 深度选择器前世今生 - guangzan - 博客园