Scoped CSS は、子コンポーネントに効いてしまう場合がある

Scoped CSS の特徴は、それが書かれたコンポーネントにしかスタイリングが効かないことでした。 これにより保守性の高い CSS を書くことができました。

しかし、Scoped CSS で書いたスタイリングが、そのコンポーネント外、具体的には子コンポーネントに効いてしまう場合があります。これについて解説します。

Scoped CSS は、子コンポーネントの一番上の要素には効いてしまう

まず親のコンポーネント App.vue が次のようになっていたとします。

参考コード

App.vue で scoped CSS を使う
<template>
  <div class="wrapper">App.vue <First /></div>
</template>

<script>
import First from "./components/First";

export default {
  name: "App",
  components: {
    First
  }
};
</script>

<style scoped>
.wrapper {
  border: 1px solid blue;
}
</style>

そして App.vue の子コンポーネントである First.vue が次のようになっていたとしましょう。 すると、本来は App.vue のスタイリングは First.vue には効かないことを普通を想定するわけですが、実際には効いてしまいます。

First.vue の .wrapper にも効いてしまう
<template>
  <!--
    App.vue の Scoped CSS は、
    子要素の一番上の要素にまでは効いてしまう
  -->

  <div class="wrapper"><h2>First</h2></div>
</template>

<script></script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>

何故ならば、親コンポーネントの Scoped CSS は、子コンポーネントの一番上の要素にも効いてしまうからです。

解決策

親コンポーネントの Scoped CSS は、子コンポーネントの一番上の要素にも効いてしまうので、その解決策の一つとしては、子コンポーネントの一番上の階層に div を置いてしまう手法があります。

参考コード

こうすれば First.vue の .wrapper には効かない
<template>
  <!--
    一枚 div が挟まれているので、
    App.vue の Scoped CSS を効かないようにできている
  -->
  <div>
    <div class="wrapper"><h2>First</h2></div>
  </div>
</template>

<script></script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>