ElementUI に Scoped CSS が適用されない問題対応策


宮崎在住エンジニアのジョウ(@JotarO_Oyanagi) です。

Vue.js 用 UI ライブラリ Element の要素に対し、Scoped CSS を使う場合に起きうる問題(後述)への対応策を紹介します。

TL;DR

  • Element の要素に Scoped CSS のスタイルが適用されないケースがある。
  • 原因は、通常の記述方法だとセレクタの子要素に data 属性がつき、そこに対してスタイルがあたるが、Element が書き出す一部の要素には data 属性がつかない。
  • 対応策としては /deep/ セレクタを使用する。

Scoped CSS とは

コンポーネントごとの CSS を書ける仕組みです。

<style scoped> とすると、そこに記述されたセレクタに対し、ユニークな data 属性がつき、その data 属性がセレクタに付加されます。

具体的にはどういうことか、公式の記述を抜粋してご紹介します。

参考:スコープ付き CSS

<style scoped>
.example {
  color: red;
}
</style>

<template>
  <div class="example">hi</div>
</template>

と記述すると、以下の状態で書き出されます。

<style>
.example[data-v-f3f3eg9] {
  color: red;
}
</style>

<template>
  <div class="example" data-v-f3f3eg9>hi</div>
</template>

data-v-f3f3eg9 という属性が付加されましたね。

セレクタに子要素を記述した場合には以下のようになります。

<style scoped>
.example .child {
  color: red;
}
</style>

<template>
  <div class="example">
    <span class="child">hi</span>
  </div>
</template>

この場合、以下の状態で書き出されます。

<style>
.example .child[data-v-f3f3eg9] {
  color: red;
}
</style>

<template>
  <div class="example">
    <span class="child" data-v-f3f3eg9>hi</span>
  </div>
</template>

親ではなく子の要素に data 属性がつきます。

Element が書き出す一部の要素には data 属性がつかない

以下の記述で書き出されたソースをご覧ください。

<style lang="sass" scoped>
.RootApp

  .el-input
    display: block
    margin: 10px auto
    width: 90%

    &__inner
      border-radius: 0
</style>

<template>
  <div class="RootApp">
    <el-input/>
  </div>
</template>

この場合、以下の状態で書き出されます。

<el-input> により .el-input.el-input__inner が書き出されています。

.el-input には data 属性がついているのでスタイルが適用されていますが、

.el-input__inner には data 属性がないため、スタイルが適用されません。

これを解決するためにどうすればいいかと小一時間調べてみると、公式にその答えが書いてありました。
上で散々挙げたスコープ付き CSSの一番下に書いてあります。

Vue の公式はマジで優秀。

親要素に data 属性をつけるには、/deep/ セレクタを使う

vue-loader v12.2.0 以上 ならば、/deep/ セレクタという仕組みがあるとのことで、それを使うと data 属性が親要素につきます。

Sass ならこう書くと

<style lang="sass" scoped>
- .RootApp
+ .RootApp /deep/

  .el-input
    display: block
    margin: 10px auto
    width: 90%

    &__inner
      border-radius: 0
</style>

こうなります。

セレクタの親要素に data 属性がついて、無事 .el-input__inner にスタイルが適用されました!

Sass ではなく、通常の CSS の書き方なら >>> を使います。

<style scoped>
.RootApp >>> .el-input__inner {
  border-radius: 0
}
</style>

おわりに

Vue 関連は「公式読め」で解決することがホント多い。

参考資料