前回は、単一ファイルコンポーネントについて説明しましたが、その中でscoped属性が付いた<style>要素についても少し触れました。
今回は、普通の<style>要素とscope属性が付いた<style scope>要素の違いについて説明します。
スコープ付きCSSとは
スコープ付きCSSとは、書かれたその単一ファイルコンポーネントの要素のみに適用されるCSSのことです。
詳しく説明するために、まずは、2種類の<style>要素が出てきた前回の内容を振り返ります。
単一ファイルコンポーネントを作成する際に設定する要素は<template>要素、<script>要素、そして<style>要素の3つでした。
この3つのうち、<template>要素と<script>要素は1つの単一ファイルコンポーネント内に1つしか書くことはできませんでした。
しかし、残った<style>要素だけは、1つのファイル内に複数個書くことができます。
複数個というと、例えばグローバルなCSSを書くためのただの<style>と、ローカルなCSSを書くためのscoped属性が付いた<style scoped>要素を書く場合が考えられます。
scoped属性が付いた<style>要素の中に書くローカルなCSSは、そのコンポーネント内だけに適用される(そのコンポーネント内のスコープを持った)CSSであることから、スコープ付きCSSと呼ばれます。
繰り返しになりますが、グローバルなCSSは、作った単一ファイルコンポーネントの全てに適用されるCSSです。一方で、ローカルなCSSとは、そのCSSが書かれた単一ファイルコンポーネントだけに適用されるようなCSSのことです。
<style>要素と<style scoped>要素の違い
それでは、<style>要素の中で設定されたグローバルなCSSと<style scoped>要素の中で設定されたローカルなCSSの適用のされ方にどのような違いがあるのか具体例を見て確認してみましょう。
グローバルなCSSとスコープ付きCSSの両方が設定されている単一ファイルコンポーネントを用意します。
その後、その単一ファイルコンポーネントを他の単一ファイルコンポーネントで使い、ブラウザに表示した場合、どのようにスタイルが適用されるのかを見てみましょう。
これから作るファイルは自分で決めた好きなフォルダ内に保存して下さい。
まずは、次のように<style>と<style scoped>を設定した単一ファイルコンポーネントを作ります。
childComponent.vue↓
<template>
<div class="container">
<h1 class="header">子コンポーネント(class="header")</h1>
<div class="contents">
<p>これは子コンポーネントの内容です。</p>
<p>この内容には、子コンポーネントに設定したスタイルしか適用されません。(class="contents")</p>
</div>
</div>
</template>
<style>
.container {
margin: 5px;
padding: 5px;
border: 1px solid black;
}
</style>
<style scoped>
.header {
color: blue;
}
.contents {
text-decoration: underline;
color: blue;
}
</style>
次に、このコンポーネントを使用するコンポーネントを作ります。
parentComponent.vue↓
<template>
<div class="container">
<h1 class="header">親コンポーネント(class="header")</h1>
<div class="contents">
<p>これは親コンポーネントの内容です。</p>
<p>この内容には、子コンポーネントで設定したスタイルが適用されません。(class="contents")</p>
</div>
<!-- ここで今作ったコンポーネントを使います -->
<child-component></child-component>
</div>
</template>
<script>
import ChildComponent from "./childComponent"
export default {
components: {
ChildComponent
}
}
</script>
<style>
.header {
color: green;
}
.contents {
color: green;
}
</style>
コマンドラインツールを使って、今作った2つ目の単一ファイルコンポーネントをブラウザに表示させます。
次のコマンドをコマンドラインツールを使って、ブラウザに表示させます。
cd 単一ファイルコンポーネントを保存してあるフォルダのパス
vue serve parentComponent.vue --open
するとブラウザに次のようなものが表示されると思います。
それでは、これからブラウザに表示されているものと、単一ファイルコンポーネントに書いた<style>要素を見比べてみます。
グローバルなCSS
ブラウザの表示を見ると、親コンポーネントと子コンポーネントのどちらともに「boreder: 1px solid black」というCSSが効いていることがわかると思います。
私が「class=”container”」と付け足して書いているように、親コンポーネントと子コンポーネントには両方に「container」というclass名がついたdiv要素があるためです。
ローカルなCSS
ブラウザの表示を見ると、親コンポーネントと子コンポーネントのどちらの「h1要素」にも「header」というclass名が付いていることがわかります。
「(class=”header”)」と書いてあるだけですが、実際にこのh1要素の部分には「header」というclass名がついています。
しかし、子コンポーネントである「childComponent.vue」という単一ファイルコンポーネントでは「header」というclass名がついた要素に対して<style scoped>の中でCSSを設定しています。
<style scoped>の中でCSSを設定していることで、子コンポーネントの「header」というclass名が付いた要素だけに対して「color: blue;」というCSSが効いています。
このように、<style scoped>の中に設定されたスコープ付きCSSはそのコンポーネント内でしか効かないようになっています。
スコープ付きCSSが他のコンポーネントの要素に効かない仕組み
scoped属性を付けた<style>要素で設定したCSSが、他のコンポーネントに効かなことは分かったかもしれませんが、なぜ効かないのでしょうか。
実は、<style>要素にscoped属性をつけることで、自動で生成されるIDを使ってCSSを適用する要素を決めるという仕組みが使われています。
これだけだと、それがどのような仕組みなのか全くわからないと思います。
<style scoped>の中身が他のコンポーネントに効かない仕組みを見るために、先程のコンポーネントをもう一度ブラウザに表示して、Chrome DevToolsを使ってHTMLを確認してみましょう。
子コンポーネントの<style scope>でCSSを適用したclass名が付いている要素を見て下さい。
「data-v-eca7a862」といった属性がついているのがわかると思います。(この属性は実行環境によって異なります)
さらに、<head>要素の部分を開いてその中にある<style>要素を確認します。
すると、2つある<style>要素のうち下の方にある<style>要素に設定されているCSSは、scope属性を付けた<style>要素に設定したCSSであることがわかります。
少しだけ違うのは、指定したclass名の横に「[data-v-eca7a862]」という属性セレクタが書かれている部分です。
属性セレクタは、その属性が設定されている要素に対してCSSを効かせるためのものです。
これらのことから分かったのは、<style>要素にscope属性をつけることで、class名だけでなく自動で生成されるIDの属性を使って、CSSを適用する要素を決めているということです。
まとめ
今回わかったこと
- <style>要素の中に書いたCSSは他のファイルのコンポーネントにも効いてしまう
- scoped属性が付いた<style>要素の中に書いたCSSはそのファイルのコンポーネントにしか効かない
- <style>要素にscoped属性をつけることで、自動生成されるIDを属性セレクタとして使って、CSSを適用する要素をコンポーネント内だけ限定することができる
コメント