CSS
vue.js

Vue.jsで style scoped な単一ファイルコンポーネントのcssをオーバーライドする

こちらのサイトを参考にしました
https://medium.com/vuejs-tips/override-scoped-css-de4275119b87

単一ファイルコンポーネントを作る時、
style scoped として CSSの影響範囲をコンポーネント内に収めるわけですが、
コンポーネント外部から内部のスタイルを変更したい場合があります。

Box.vue
<template>
  <div class="box">
    <div class="message">
      <slot></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: 'box'
}
</script>

<style scoped>
.box {
  display: inline-block;
}

.box .message {
  background-color: orange;
  padding: 1em;
}
</style>

前提として、Boxコンポーネントは登録済みです。

main.js
import Vue from 'vue'
import App from './App.vue'
import Box from './Box.vue'

Vue.component('box', Box)

new Vue({
  el: '#app',
  render: h => h(App)
})

次のようなテンプレートを記述したとします。

App.vue
<template>
  <div id="app">
    <box class="green">.green</box>
    <box class="green override">.green.override</box>
    <span class="parent"><box class="green">.parent .green</box></span>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
    }
  }
}
</script>
<style scoped>

</style>

この時の表示は以下のようになります。

image.png

ここで、ボックスの色をオレンジから緑に変えたいとします。

この時のHTML(1つめのボックス部分)はこのようになっています。

image.png

単純に1つめのボックスに対してCSSを記述してみます。

App.vueの一部
<style scoped>
.green .message {
  background-color: green;
}
/* or */
.box .message {
  background-color: green;
}
</style>

まとめて2つ書きましたが、scopedされているため、このどちらも作用しません。

次のように属性セレクタをつけることで作用させることができますが、
セレクタに用いる属性値を事前に知ることはできません。

.green .message[data-v-1461803c] {
  background-color: green;
}
/* or */
.box[data-v-1461803c] .message[data-v-1461803c] {
  background-color: green;
}

scoped スタイルで入れ子のセレクタが必要なら、CSS に対して >>> オペレータを使用する必要があります。

引用元
https://vue-loader.vuejs.org/ja/features/scoped-css.html

と引用元に記載されているのを参考に次のようにしてみますが、やはり効果がありません。

.green >>> .message {
  background-color: green;
}

どうやらセレクタは期待通りに動作しているようです。

image.png

しかし、CSSの適用順によってうまく効果が出ていないことがわかります。

どちらも詳細度が同じ為、順序が優先されています。

image.png

詳細度確認
https://specificity.keegan.st/

1つ目のボックスのようにクラス1つでは詳細度が足りないため、2つ目のボックスのようにクラスを2つ付けます。

    <box class="green override">.green.override</box>

これに対して、次のようにCSSを記述することで詳細度を上げ、指定を優先させることができます。

css
.green.override >>> .message {
  background-color: green;
}

image.png

または、3つ目のボックスのように親要素をつけることでも実現できます。

<span class="parent"><box class="green">.parent .green</box></span>
.parent .green >>> .message {
  background-color: green;
}

これで、望みどおりのスタイルが適用できました。

image.png