Vue.jsで小さなコンポーネントを作っていると時折デザインの一部をコンポーネントを呼び出す側で自由に決定させたい時があります。この記事ではそのやり方を紹介します。
コンポーネントの持つ値をCSSに伝えるために重要な機能はCSSにおける変数であるカスタムプロパティです。
カスタムプロパティ (–*): CSS 変数 – CSS: カスケーディングスタイルシート | MDN
CSS カスタムプロパティ (変数) の使用 – CSS: カスケーディングスタイルシート | MDN
カスタムプロパティは次のように用います。カスタムプロパティの適用対象は定義したHTMLElementの子方向の要素全てです。
div.hoge-box {
--hoge-box-width: 3em; /* --hogeで宣言 */
width: var(--hoge-box-width); /* var(--変数名)で使用 */
}
div.hoge-box > div {
width: calc(var(--hoge-box-width) / 6) /* calcでも使える */
}
html {
--global--base-color: hsl(0, 0, 0); /* html, :root, bodyの様な広い範囲で指定するとグローバル的に使える */
}
コンポーネントのルートエレメント上でコンポーネントの持つ値を用いてカスタムプロパティを定義することでCSSへ任意の値を与えます。これは例えば次のようにpropsで与えられた値をcomuputedでまとめ、まとめた値をルートエレメントであるdiv.check-boxのスタイルとして定義、定義した変数をCSS内で扱う、というやり方です。
<template>
<div
:style="styleVariables"
class="check-box"
>
<div class="check"/>
</div>
</template>
<script>
export default Vue.extend({
props: {
checkboxWidth: {
type: String,
default: '3em',
},
},
computed: {
/**
* このコンポーネント中で用いるCSS変数をまとめる.
* @return {object}
*/
styleVariables() {
return {
'--checkbox-width': this.checkboxWidth,
};
},
},
};
</script>
<style lang="scss" module>
.check-box {
--checkbox-width: 3em;// 事故防止のデフォルト値
border: 2px solid #9e9e9e;
border-radius: 2px;
width: var(--checkbox-width);
min-height: var(--checkbox-width);
display: flex;
justify-content: center;
align-items: center;
}
.check{
position: relative;
top: calc(var(--checkbox-width) / 6); // def=0.5em
left: calc(var(--checkbox-width) / -20);// def=-0.15em
transform: rotate(-45deg);
transform-origin: left top;
border-left: 2px solid #000;
border-bottom: 2px solid #000;
width: calc(var(--checkbox-width) / 2.4 * 1.618); // def=2.0225em
height: calc(var(--checkbox-width) / 2.4); // def=1.25em
}
</style>
上記コードの動作は次のデモの通りです。
いたるところでサイズをemで指定していますが変数を介しているためデザインを崩さずデザインを容易に変更できます。変数はコンポーネントのプロップで決定しているため、コンポーネントを呼び出す側が安全にデザインを変えられます。この変数渡しのやり方に加えて、アニメーションや状態の定義と変化を用いることで自由に簡単に扱える最小単位のコンポーネントを作りやすくなります。
余談ですが、カスタムプロパティを用いる際、CSS独立ファイルでは未定義の変数名を呼び出そうとするか、定義セレクタを多量にコピペすることになり辛くなります。SCSSの様な階層構造を定義できるCSS拡張言語を用いると安全に簡潔に記述できます。
// scssコード
div.hoge-box {
--hoge-box-width: 3em; // --hogeで宣言
width: var(--hoge-box-width); // var(--変数名)で使用
div { // div.hoge-box divと同じ意味になる
width: calc(var(--hoge-box-width) / 6) // calcでも使える
}
}