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

陟上晴明發表於2023-02-21

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 - 部落格園

本文參與了SegmentFault 思否寫作挑戰賽,歡迎正在閱讀的你也加入。

相關文章