【Vue CLI】<style scoped>で子コンポーネントのスタイルがどう変わるか検証した


結論

<style scoped>で子コンポーネントスタイルを設定したら、そのスタイルは子コンポーネントの一番上のルートにだけ適応される

というルールを検証した結果、その通りだった。

参考:
vue-loader -子コンポーネントのルート要素-
vue-loaderのScoped CSSのスタイルが子コンポーネントのルート要素に効いてしまって辛い

Vue CLIを触り初めて1週間、コンポーネントの<style>の書き方が間違っていて、思い通りのレイアウトにならず苦労した。
後日また同じことで悩まないように、やった手順とよくなかった点をメモしておく。
そしてこの記事が誰かのためになれると嬉しい。

検証画面の構成

コンポーネントの構成

作成したファイル


- src
    - components
        - ContinueButton.vue
    - views
        - Pj002.vue

ソース

↓コンテニューボタンの単一コンポーネント

ContinueButton.vue

<template>
  <div class="continue-container">
    <p>
      CONTINUE
      <span class="continue-text">
        >
      </span>
    </p>
  </div>
</template>


↓メインページ *コンテニューボタンのスタイルはすべてココに書いている

Pj002.vue
<template>
  <div class="background">
    <main>
      <ContinueButton></ContinueButton>
    </main>
  </div>
</template>

<script>
import ContinueButton from '@/components/ContinueButton.vue';

export default {
  name: 'Pj002',
  components: {
    ContinueButton,
  },
};
</script>

<style>
@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap');

/* Pj002.vue全体の背景 */
.background {
  height: 90%;
  position: absolute;
  top: 10%;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: lightblue;
}

/* コンテニューボタンの白いボーダーラインなどを設定 */
.continue-container {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 500px;
  height: 150px;
  border: 5px solid #ffffff;
  text-align: center;
  line-height: 45px;
  opacity: 1;
}

/* コンテニューボタンの文字フォントなどを設定 */
.continue-container p {
  position: absolute;
  width: 100%;
  top: 20%;
  left: 60%;
  transform: translate(-50%, -50%);
  letter-spacing: 1.6px;
  color: #ffffff;
  font: 48px/32px Bebas Neue;
  opacity: 1;
}

/* コンテニューボタンの"CONTINUE"と">"の間の余白を設定 */
.continue-text {
  text-align: left;
  margin-left: 80px;
}
</style>


<style>を変えたらどうなるか

<style>のままの場合

見た目

理想通り。
スタイルがscopedになっていないので、CSSはグローバルで定義されていることになり、コンテニューボタンのレイアウトも問題なく表示される。

<style scoped>にした場合

見た目

変わったところ、変わらなかったところ

  1. 白いボーダーラインは何も変わらずきちんと表示されている
  2. 文字のフォントが変わっている
  3. "CONTINUE" と ">" の間の余白がなくなっている

<template>のclass属性も上記の順番で設定している。

冒頭の結論で出した通り、やはり子コンポーネントの1番上の要素は<style scoped>にしたにも関わらずレイアウトが適応されている。
それ以下のスタイルは適応されていない。

ちなみに<style module>にした場合

見た目

変わったところ、変わらなかったところ

子コンポーネントのスタイルは一番上の要素であっても適応されない。 ・・・!!?
(※"CONTINUE >"という文字列も表示されなくなった点については理由がわかっていないので、どなたかわかる方がいれば教えていただきたいです。)

ソース

class属性の記載方法がv-bindに変わるのでソースを載せておく。

ContinueButton.vue

<template>
  <div :class="$style.continue_container">
    <p>
      CONTINUE
      <span :class="$style.continue_text">
        >
      </span>
    </p>
  </div>
</template>

Pj002.vue

<template>
  <div :class="$style.background">
    <main>
      <ContinueButton></ContinueButton>
    </main>
  </div>
</template>

<script>
import ContinueButton from '@/components/ContinueButton.vue';

export default {
  name: 'Pj002',
  components: {
    ContinueButton,
  },
};
</script>

<style module>
/* Pj002.vue全体の背景 */
@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap');

.background {
  height: 90%;
  position: absolute;
  top: 10%;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: lightblue;
}

/* コンテニューボタンの白いボーダーラインなどを設定 */
.continue_container {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 500px;
  height: 150px;
  border: 5px solid #ffffff;
  text-align: center;
  line-height: 45px;
  opacity: 1;
}

/* コンテニューボタンの文字フォントなどを設定 */
.continue_container p {
  position: absolute;
  width: 100%;
  top: 20%;
  left: 60%;
  transform: translate(-50%, -50%);
  letter-spacing: 1.6px;
  color: #ffffff;
  font: 48px/32px Bebas Neue;
  opacity: 1;
}

/* コンテニューボタンの"CONTINUE"と">"の間の余白を設定 */
.continue_text {
  text-align: left;
  margin-left: 80px;
}
</style>


開発者ツールでの確認結果

<!-- --> になっている

まとめ

<style scoped>にしても、子コンポーネントの一番上のルートにはスタイルが適応されてしまうので注意すべき。
一部だけ反映されるから「CSSどっかいじってしまったかな?」なんて微調整し始めると沼。
公式のスタイルガイドにて、<style scoped>の使用は必須レベルで推奨されているので、きちんと使いこなせるようになりたい。

参考:
スタイルガイド -コンポーネントスタイルのスコープ-
【Vue.js】Scoped CSSよりCSS Modulesの方がベターだった件