CSS変数とSASS変数
以前、CSS変数についての僕の考えを書いた記事があった。もともとこのプロパティにはあまり大きな期待を抱いていなかったし、SASSの変数に慣れていた僕にとって、このCSS変数はむしろ使い勝手の悪い中途半端なシステムのように見えていた。だが、もし君も同じように考えているなら、この記事 Why should you care Css variables を参考にしてみてほしい。
CSS変数は登場してからある程度の期間が経ち、ブラウザのサポート状況もそこまで悪くはない。おそらく皆も一度は、「これらの変数の機能はSASSでほぼすべて実現できるし、SASSの関数や型(list、map)と組み合わせれば、変数の柔軟性はさらに強力になるのではないか」と考えたことがあるだろう。
しかし、ここで僕が共有したいのは、CSS変数の真に優れているポイントがどこにあるのかということだ。
この記事では、すでに読者がCSS変数に関する基礎知識をある程度持っていることを前提としている。
ちなみに、この記事ではCSS変数の使い方を網羅的に書いているわけではないので、何かアドバイスや意見があればぜひ教えてほしい。いずれ時間を作って、より包括的な記事を書き直すつもりだ。
サポート状況
| Browser | Version |
|---|---|
| Chrome | 49 |
| Firefox | 42 |
| Safari | 9.1 |
custom property
プロパティのように振る舞わせたときに初めて、通常のプリプロセッサよりも強力になる
まず明確にしておきたいのは、CSSの仕様 において、変数(variable)は実際には custom property(カスタムプロパティ)と呼ばれているという点だ。これはどういう意味だろうか?「変数」と「プロパティ」で頭が混乱してしまうかもしれない。
焦る必要はない。つまりCSS変数を使う際には、単なるプログラミング的な「変数」としてではなく、通常のCSS「プロパティ」として捉えるべきだということだ。以下では、CSS変数の使い方についていくつか紹介していく。
なぜCSS変数を使うべきなのか
- これらのプロパティを使うのにプリプロセッサは不要。
initialやinheritを使って階層構造を作ることができる。- ブラウザが必要なときに再レンダリングしてくれる。
- アクセス可能であり、JavaScriptを使って操作できる(後ほど説明する)。
プロパティの特性
CSSプロパティである以上、当然ながら以下のような特性を持つ:
- いわゆる
initialやinheritといった値が使える - 呼び出し方は
var(--variable-name) inline-styleの中に記述できる- JSから値の取得や設定ができる
中でも最大の目玉は、inline-styleに書ける点と、JSと連携して値の取得・設定ができる点だ。これこそがSASSやLESSなどのCSSプリプロセッサとの最大の違いであり、CSSに新たな可能性をもたらしてくれる。さっそくいくつかの具体例を見ていこう。
:root {
--mainColor: #abc;
--subColor: #ccc;
}
h1 {
color: var(--mainColor);
}
ここで :root に宣言された値はすべての要素に継承される。これこそが custom property の特性だ。
inline-style
プロパティなので、当然このように書くことができる。
<h1 style="color: var(--mainColor);">
Hello, world
</h1>
一見すると大して珍しいことではないように思えるかもしれない。同じことはクラスとSCSS変数を組み合わせても実現できるからだ。しかし、これによってinline-styleを書く際の選択肢と可能性がさらに広がる。
react inline style
例えばReactにおいて、inline-styleを書く必要がある場面がある。しかし色の定義がSCSSの管理から外れてしまうため、往々にして非常に扱いづらくなる。カラーコードを直接ベタ書きして後から修正する羽目になるか、あるいはJS側で別途カラー変数テーブルを保持するか、もしくはカラー変数ごとにクラスを割り当てるのが関の山だった。
今はCSS変数があるため、非常に便利に使うことができる。
const styles = {
heading: {
fontSize: "14px",
color: "var(--mainColor)",
},
warn: {
color: "var(--warnColor)",
},
}
const heading = ({ title }) => <h1 style={styles.heading}>{title}</h1>
※この記事ではCSS変数の紹介に焦点を当てているが、実際にはReactにおけるスタイリングの管理方法は他にも優れたアプローチが存在する。
grid
ガター(gutter)の設定も、今やCSS変数を使って実現できる。つまり、@media クエリを使って変数の値を切り替えることができるのだ。これは通常のプリプロセッサでは不可能なことである。
JSによる制御
JavaScriptを操作することで、CSS変数の値の設定や取得を簡単に行うことができ、ViewとJSの分離を実現できる。例えば、何らかの演出のためにJSで値を取得し、それをCSSに渡したいとする。従来であれば、JavaScriptで計算を行った後、その計算結果をinline-styleで要素に直接適用することが多かった。
しかし、それでは以下のような問題が生じる可能性がある:
- その値が意図したものでなかったり、CSS側でその値に対してさらに独自の加工を加えたい場合がある。そうなるとJavaScriptのコードを修正し直さなければならず、非常に面倒だ。
- inline-styleで直接値を書き込んでしまうため、通常のCSS側からは手出しができなくなる。
CSS変数が導入されたことで、値の設定や取得は極めて手軽になった。
値の取得
HTMLElement.style.getPropertyValue("--mainColor")
値の設定
HTMLElement.style.setProperty("--mainColor", "#abc")
したがって、イベントリスナーを登録して、注目している数値をCSS変数に流し込むことも当然可能だ。
const element = document.addEventListener("mousedown", e => {
// some HTMLElement;
element.style.setProperty("--pageX", e.pageX)
element.style.setProperty("--pageY", e.pageY)
})
サポート状況の確認
現在のブラウザがCSS変数をサポートしているかどうかを確認したい場合は、CSS.supports の構文を使って判定できる。
CSS.supports('(--css: variables)') CSS.supports('not (--css: variables)')
今後の課題
変数を管理する方法が増え、JavaScriptから変数の値を設定するケースも出てくるため、これらの変数を扱う際にはより注意を払う必要がある。
- 変数の宣言を一元管理する:グローバル変数は1つのファイルまたはディレクトリにまとめておくと、後のメンテナンスが楽になる。CSS変数を宣言する場合も同様だ。
- JSから値を設定するための変数には、目印としてプレフィックス(接頭辞)を付けると良い。例えば
--js-pageXなどのように命名する。
結論
この記事では、CSS変数の使い方や活用シーンを紹介した。以前の僕もCSS変数は使いづらいと感じていたし、記述方法が見た目としてイマイチなうえ、便利な関数操作もないと思っていた。
しかし、CSS変数が「カスタムプロパティ(custom property)」であるという本質を理解すると、従来のCSSでは突破できなかった新たな可能性が見えてくる。SASSかCSS変数のどちらか一方を無理に選ぶ必要はない。むしろ両者を組み合わせることで、これまでにない強力な表現や設計を実現できるのだ。
関連記事
- Three.js で僕の部屋を表現する 僕が React Three Fiber を使って実際の自分の部屋をブラウザ上に再現し、実世界のオブジェクトを目録に見立て、空間の記憶を通してここ数年の生活と仕事について語った話。
- フロントエンドで画像を扱う際に注意すべきこと Jake Archibaldの記事を起点に、現代のレスポンシブ画像の書き方を整理する。なぜwidth/heightを付ける必要があるのか、CSSのaspect-ratioはいつ使うべきか、AVIFとWebPの選び方、そしてpicture/source/srcsetを使ったモバイル向け画像の切り替えについて。
- CSS field-sizing — たった1行のCSSでフォーム要素を自動リサイズする かつてtextareaの自動高さ調整は、JavaScriptでscrollHeightを監視するしかなかった。しかしCSSのfield-sizing: contentなら、わずか1行で代替でき、textarea、input、selectに対応している。本記事では従来のやり方のペインポイントと、field-sizingの使い方をまとめる。
- リンクの下線をもっと見栄え良くする:text-underline-offset デフォルトでは下線と文字が近すぎて、このスタイルを好まないデザイナーもいるし、僕自身もあまり綺麗ではないと感じていた。