イケてるフロントエンドエンジニアになりたい方以外は絶対に見ないでください〜CSSカスタムプロパティのお話〜

こんにちは!何時だろうが朝は眠い、フロントエンドエンジニア1年生のイリサワです。
未経験でニジボックスに入社してはや3ヶ月… 完全にこれ状態ですけど、割と楽しくやっています。

さて、イケてる風は常に海の向こうから吹いてくると教えられたので、
早くイケてるフロントエンドエンジニアになりたい筆者は海外のテックブログにも目を通しています。
これでライバルの有象無象に3馬身くらい差を付けられること請け合い!

そんなわけで、最近読んで「勉強になる〜!」と思った海外記事を、折角なので色んな人に見てもらおうと思い、翻訳してみました!(※元のサイトにはちゃんと転載許可とってます、安心安全コンプライアンス)

今回は、ネイティブCSSで変数が使えちゃう、CSSカスタムプロパティについてのお話です。
Chrome49でのサポート開始が記憶に新しいですね〜。
ではではどうぞ!(訳注は翻訳の一番下にまとめて記載しております)

CSSカスタムプロパティを使ってみよう – var()関数によってCSSで変数の使用が可能に –

元の記事:
Custom properties define a new value type in CSS that allows for the use of variables through the var() function.
著者:
Hui Jing Chen
記事提供サイト:
codrops

SassやLessなどのCSSプリプロセッサを使用する理由として最もよく挙げられるのが、スタイルシートに変数が使用できるということ。カラーコードやマージンの値を変更するのに、何千行もあるCSSをいちいち探すのは面倒ですしね。検索と置換というツールもあるけれど、1つ2つの漏れが出るかもしれません。ところが変数を使えば、変更は1箇所で済みますし、加えた変更がコード全体に適用されることが保証されているわけです。

CSSプリプロセッサの問題は、ブラウザにコードを読み込ませるためにはCSSにコンパイルする必要があるということ。コンパイルしなければならないので、結局これらの「変数」は本質的には静的であり、実行時に動的に変更することはできないのです。

CSSカスタムプロパティなら、加えた変更が実行時に適用される、本当の意味での動的な変数が使用できます。これはつまり、値が変わればブラウザがその通りに再描画を実行できるということ。さらに、これはCSSそのものに備わっている機能なので、コンパイルの必要もありません。これに加えて、継承やカスケードといったCSS標準の動きも備えています。これはCSSプリプロセッサの変数では実現できなかったことです。

カスタムプロパティ値の設定ルール

CSSカスタムプロパティを使えば、開発者は自分で名前をつけたプロパティに任意の値を割り当てることができます。公式には、カスタムプロパティは-(ダッシュ)2つから始まる任意の有効な識別子(例:–quux)を指します。大文字と小文字は区別されるので、–quuxと–QUUXは同一の値を参照するわけではありません。

ではここで、CSSカスタムプロパティを定義して使うための簡単な例を見てみましょう。以下の例では、–primary-colorをカスタムプロパティとして定義しています。

:root {
  --primary-color: #0099cc;
}

h1 {
  color: var(--primary-color);
}

a {
  color: var(--primary-color);
}

–primary-colorの値を変更すると、h1要素やa要素の値も変わります。

カスタムプロパティはドキュメント内のどの要素でも宣言可能で、通常の継承やカスケード規則に則って処理されます。
下記の例を見てみるとわかりますね。

See the Pen Simple Example – CSS Custom Property by Yuki Irisawa (@yk1979) on CodePen.

var()関数の使い方

ブラウザが変数に割り当てられた値をプロパティの値として代入するのにvar()関数を使用するため、CSS変数もvar()関数にによって動作します。
構文はこんな感じです。


var() = var( <カスタムプロパティの名前> [, <宣言値> ]? )

var()関数は、プロパティ名、セレクタ等、プロパティの値以外のものとして使うことはできません。以下はvar()関数の無効な使用例です。

/* 変数をプロパティの名前として使用することはできない */

.baz {
  --side: padding-left;
  var(--side): 1em;
}

/* 変数をプロパティの一部として使うことはできない */
.qux {
  --gap: 0.5;
  margin-left: var(--gap)em;
}

var()関数は、変数として、要素のCSSプロパティの任意の値の代わりに使用できます。以下の例を見てみましょう。渡されている最初の引数は代入されるカスタムプロパティの名前で、2つ目の引数はフォールバック値です。フォールバック値は、指定されたカスタムプロパティが無効な場合に使用されます。

p {
  margin: var(--margin, 1em 2em);
}

一つ注意しなければならないのが、var()関数は計算値の時に代入されるということです(※訳注1)。つまり、計算値の時点で、代入の際のvar()関数の計算結果が無効であった場合、CSSの宣言そのものも無効になってしまうということです(※訳注2)
CSS confでの講演でLea Verouが指摘していた、別の問題もあります。url()関数でのみ、構文解析の動作がおかしくなり、CSS変数が正しく動作しないのです。

/* これだと動かない */
.element {
  --img: "sad";
  background: url("img/" var(--img) ".jpg") center / cover;
}

/* でもこれだと動く */
.element {
  --img: url("img/cat.jpg");
  background: var(--img) center / cover;
}

カスタムプロパティの導入で、CSSでこれまでになかった色々な要素が使えるようになります。例えば、実際に使われている箇所から文字列を切り離して変数扱いにしておけば、国際化対応してあるページの維持もしやすくなるのです。こんな感じですね。

:root,
:root:lang(en) {
  --external-link: "external link";
}

:root:lang(de) {
  --external-link: "Externer Link";
}

a[href^="http"]::after {
  content: " (" var(--external-link) ")";
}

カスタムプロパティを別のプロパティの一部として使うことはできませんが、calc()関数の中でなら、プログラムで新しい値を作り出すのと同じような要領で使用可能です。

:root {
  --spacing: 20;
}

.cell {
  margin-bottom: calc(var(--spacing + 10px));
}

カスタムプロパティを使用するもう1つのメリットは、その動的な性質を利用したコンテキスト・スタイリング(※訳注3)が可能ということです。ではここで、基本のスタイルが設定されていて、設置場所によってほんの少しだけスタイルが変わるボタンの例を見てみましょう。

カスタムプロパティを使わずにコンテキスト・スタイリングを行う場合、下の例のように、子孫セレクタの概念を利用するのが一般的なやり方でしょう。しかし、この方法では、要素を特定して管理するための記述はどんどん複雑になってきますし、プロジェクトが大きくなってくるとメンテナンスの問題にも繋がってきます。もしかしたら、ヘッダー内のボタンの見た目が全然違うものになる時がくるかもしれませんよね。

.o-btn {
 background: #30abd5;
 border: 1px solid #30abd5;
 color: #fff;
}

.c-header .o-btn {
 background: transparent;
 border: 1px solid #237dac;
 color: #237dac;
}

カスタムプロパティを使えば、ヘッダー内のボタンコンポーネントを特定のスタイルに固定せず、ボタンコンポーネントが置かれているコンテキストの内容を変更できます。こうすることで、上で述べたような、要素を特定して管理する上での問題を考えなくても済むようになります。

.o-btn {
  background: var(--btn-bg, #30abd5);
  border: 1px solid var(--btn-border, #30abd5);
  color: var(--btn-txt, #fff);
}

.c-header {
  --btn-bg: transparent;
  --btn-border: #237dac;
  --btn-txt: #237dac;
}

ライブデモ

ここから、これまでのセクションで説明したテーマの例をデモで確認できます。

See the Pen Application – CSS Custom Property by Yuki Irisawa (@yk1979) on CodePen.


カスタムプロパティを使うと、メディアクエリ内でCSS変数を使うことができます。これはプリプロセッサの変数では不可能でした。次の例では、要素間の間隔を変えたり、変数を使ってレイアウト内のカラム数を調整したりすることができます。別のウインドウでデモを開いて、画面をリサイズするとどうなるか見てみてください。

See the Pen Media Queries – CSS Custom Property by Yuki Irisawa (@yk1979) on CodePen.

ブラウザサポート

CSS変数(カスタムプロパティ)

スタイルシート内での宣言とカスケード変数が使えます。
段階:W3C勧告候補
こちらのバージョンからサポートされています。

デスクトップ

  • Chrome49
  • FireFox31
  • IE
  • Opera35
  • Safari9.1

モバイル、タブレット

  • iOS9.3
  • Android56
  • Opera
  • Chrome59
  • FireFox54
  • 対応!
  • 非対応…

参考:CanIUse

参考文献

CSS Custom Properties for Cascading Variables Module Level 1
CSS Custom Properties for Cascading Variables Module Level 1
Using CSS variables
Conditions for CSS Variables
Locally Scoped CSS Variables: What, How, and Why
Lea Verou – CSS Variables: var(–subtitle);

関連エントリ

calc()
Media Queries


訳注1:CSSの「値」は、スタイルシートにコードが記述されてから最終的にレンダリングされるまでの計算の過程で、いくつかの「途中の値」を経由します。計算値とは、この「途中の値」の1つです。この辺りの話については、古い記事ですがこちらにわかりやすくまとまっています。MDNによる計算値の定義はこちら
訳注2:var()関数の計算結果が無効な値だった時にCSSの記述全体が無効になってしまう例については、W3Cの仕様書の日本語訳ページの、「3.1 無効な変数」というセクションに載っているのでこちらも是非見てみてください。
訳注3:こちらの記事によれば、要素が DOM 上でどこに位置するかに応じてスタイリングすること。これもカスタムプロパティについての記事で、とっても面白くてためになるので是非読んでみてください。


いかがでしたか??
IE非対応などの制限もありますが、ネイティブCSSでここまでできちゃうなんてすごいですよね〜!
まだCSSプリプロセッサで消耗してるの?という時代は、もうすぐそこなのかもしれません…

またいい感じの記事を見つけたら、ご紹介したいと思います!

RECRUIT

私たちと一緒に「魂を込めたモノづくり」をしませんか?
ニジボックスではクリエイターを随時募集しています。
気軽にお問い合わせください。