グラデーションアニメーションも!?CSS変数の便利な使い方~CSSとJavaScriptの橋渡し~

フロントエンド
エンジニア

T.K

全世界の皆様、お久しぶりです( ^ω^)
フロントエンドエンジニアのT.Kです。

フロントエンド
エンジニア

T.K

最近ふと思い立って
←この入社当時に作ってもらった似顔絵について、ChatGPTに頼んで髪の長さを今に合わせて腰の下まで伸ばしてもらいました。

弊社マスコット
キャラクター

ロージー

なんかロングヘアT.K、悲しそうしゅこ・・・

フロントエンド
エンジニア

T.K

多分麻雀で負けたんやな・・

前回書いたAI活用の記事から約1年、なんとChatGPTでも画像生成ができるようになっています。

やはり対話形式で画像に変更を加えられるというのは非常に便利なもので、

私も有料会員になり、存分に画像生成を楽しんでいます。

最近だとガラスで出来たフルーツを包丁でカットする動画といった、現実では実現不可能なことを行う動画も作れるAIツールなども登場し・・・

日進月歩なAIツールに、創作活動を行う者として大きな期待と夢とロマンを抱くと同時に

「知らないうちに便利なツールを見逃して、時代に取り残されたらどうしよ」と

若干びびっている今日このごろです。

 

さて、見逃しているかもしれないものはAIツールに限らないわけでございまして。

今回はCSSを学習する上で皆様が見逃しているかもしれない(というか私が途中まで見逃してた)便利機能の1つ、

CSS変数についてご紹介!

CSS変数とは

カスタムプロパティCSS 変数カスケード変数と呼ばれることもあります)は、CSS の作者によって作成され、文書全体で再利用可能な特定の値を表すエンティティです。これらは、@property アットルールまたはカスタムプロパティ構文(例: --primary-color: blue;)を使用して設定します。 カスタムプロパティは、CSS の var() 関数(例: color: var(--primary-color);)を使用してアクセスします。

出典 MDN

CSS変数はCSS上で使用可能な変数です。

(正式名称は「CSSカスタムプロパティ」ですが、本記事では直感的に分かりやすい名称である「CSS変数」と呼称します)

SCSSにも変数機能があり、同一の値を変数化しておけて非常に便利ですが

CSS変数には、SCSSの変数とは違った特徴があります。

  • 実行時に変更できる
  • JavaScriptと共有できる

実行時に変更できる

SCSSの変数はコンパイル時に固定値へ変換されるため、実行後に変更することはできません。

一方、CSS変数はブラウザ上でも「変数」として残るため、JavaScriptやCSSの中で値を動的に変更できます。

たとえばテーマカラーやアニメーションの速度など、状況によって変化させたい値を管理するのに便利です。

JavaScriptと共有できる

CSS変数は JavaScriptから読み取ったり書き換えたり できるため、

スタイルとスクリプトの両方で同じ値を扱えます。

これにより、デザインと挙動を一貫させたインタラクティブな表現が容易になります。

CSS変数の記法

では早速使ってみましょう!

ここでは、CSSおよびJavaScriptでのCSS変数の扱い方を紹介します。

CSS変数の指定方法

CSS変数は2つの指定方法があります。

/*方法1 基本的にはこっちでOK*/
:root{                          /*「:root」内で指定した値は、html要素内で使用可能*/
  --color-1: red;               /*変数名:値 というふうに指定する。変数名は「--」から始まっている必要がある*/
}
.hoge{
  --length-1: 100px;              /*要素「.hoge」内のみで使用できる値を指定*/
}

/*方法2 この値を使用してアニメーションする場合はこっちで指定する必要がある*/
@property --color-1 {
  syntax: "<color>";            /*型を指定*/
  inherits: true;               /*下位要素に継承するかどうかを指定*/
  initial-value: red;           /*初期値を指定する。方法1の値と同一*/
}
.hoge{
  @property --length-1 {         /*要素「.hoge」内のみで使用できる値を指定*/
    syntax: "<length>";
    inherits: true;
    initial-value: 100px;
  }
}

CSS変数の使用方法

では指定したCSS変数を使用してみましょう。

下記CodePenをご覧ください。

方法1

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

方法2

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

  • var()」で囲まなければならない
  • --」から始めなければならない

以外、だいたいSCSS変数と同じですね!

CSS変数をJavaScriptで取得・設定する方法

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

CSS変数の便利な活用法

基本的なことが分かったところで、具体的な便利な活用法を見ていきましょう。

ここではSCSS変数との違いに注目し、CSS変数でしか出来ないことを紹介します。

SCSSが使えない環境で変数を使用する

自社で0からコーディングを行う案件ではSCSSを使えることが多いかと思いますが、

他社が作ったコードを編集する案件ではSCSSを使用できないことがあります。

こんな場合、CSS変数がSCSS変数と同じように使えるので便利です。

CSSプロパティの値が長く、一部だけ変えたい場合、そこだけCSS変数にする

例えばbox-shadowの影の大きさのみを変更したい場合。

今後一切変える予定のない値までも何回も何回も書き換えるのは大変なものです。

そこで、影の大きさのみをCSS変数化しましょう。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

この手法は、box-shadowのような複数書かなければならない値を変更するのに役立ちます。

ダークモードを楽に作る

ダークモードの実装も、CSS変数を使用すると簡単に実装できます。
使用する色をそれぞれCSS変数として指定しておき、クラス「.-dark」がついているときに値を変更します。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

 

CSS変数を変更するだけで色が反転する!!便利!!!

文字拡大/縮小機能を作る

ウェブサイトに文字を拡大/縮小する機能をつけたい場合に、CSS変数が大活躍。

SCSS変数にはない「値をあとから変えられる」という特性を利用します。

JavaScriptで全要素の文字サイズを抽出して、それに倍率を掛けて設定して・・といった激重・激ややこな操作を避けられます。便利。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

なお、文字サイズについては、

  • html要素に対しfont-size:1px
  • 拡大/縮小対象のフォントのみremで指定
  • JavaScriptでhtml要素のfont-sizeを変更する

という手もあります。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

ヘッダの高さを変数化し、それにまつわる値を自動的に設定

ヘッダの高さが関係する値(例:<main>内のpadding-top、アンカーリンクのスクロール位置)を、ヘッダの高さが変わるパターンについて全部書かなあかん・・
こんな経験あるのではないでしょうか?

そんな場合はヘッダの高さをCSS変数に格納してしまいましょう。

下記サンプルでは画面横幅が小さいときヘッダの高さが変わっていますが(EDIT ON CODEPENをクリックしてご覧ください)、

  • ヘッダの高さの値にまつわる値をCSS変数で設定している
  • JavaScriptで上記の値を取得・使用している

ということにより、DRY原則に従いメンテナンス性が向上しています。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

これでheaderの高さにどんだけ変わるパターンがあっても平気です。やったね。

SCSS変数ではheaderの高さの変化に自動的に対応できないので、

このようなある可変の値に依存した値を複数の箇所で使う場合にもCSS変数が役立ちます。

CSS変数を@propertyで指定し、アニメーションを実装する

先程、CSS変数の指定方法は2つあると書きました。

では、この2つの方法は何が違うのでしょうか?

実は、@propertyを使って指定すると、従来であれば実装出来なかったタイプのアニメーションを実装できます。

変数指定方法1(--hoge: piyo):アニメーションは動かない

記述が楽で済むこの書き方(具体的な記法は下記CodePenをご覧ください)。

基本的にはこちらで問題ないですが、ただ変数名と値を記述しただけであり、どのような型なのかが定義されていないため

アニメーションの変数として使いたい場合にはスムーズにアニメーションできません。

例えば下記のようなアニメーションは動きませんね。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

変数指定方法2(@property):アニメーションが動く

一方こちらはちょっと記述量が多い書き方。

変数の値以外に

  • 値の型
  • 下位要素に継承するか否か

を指定します。

この方法ですと型が指定されているので、期待通りアニメーションしていますね。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

この話、実は私もこの記事を書くにあたって、初めて知りました・・・

工夫次第で他にも従来できなかった実装が出来そうな気がします。

下記に私が作った、CSS変数が便利なアニメーションをいくつか掲載します。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

以下は、パラメトリック方程式で定義される曲線の別バージョンです(重いのでリンクを貼ります)。

ホバー効果を楽に作る

例えば下記の1つ目のような、2色構成のボタンを実装する場合。

ホバー時にその2色を反転させたい場合、その2色をそれぞれCSS変数として指定しておくと楽に実装できます。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

ホバー時にトランジションを効かせたいので、CSS変数は@propertyを使用して設定します。

それぞれの要素に対しトランジションのプロパティを1個ずつ指定して・・という地味にめんどくさい工程を省けます。

なお、SCSS変数だとコンパイル後に定数となるため、同様にやると失敗します(下記)。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

CSSのみでカウントアップ

コーポレートサイトの実績ページにありがちな、数字がカウントアップするアニメーション。

従来はJavaScriptで頑張って実装していましたが、@propertyでCSS変数を指定すると、数字部分はJavaScriptなしで実装することができます。

カウントアップ後の値をHTMLのstyle属性で指定することで、部分毎に任意の値までカウントアップすることが可能です。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

::before要素にCSS由来の数字を表示できることを利用します。

ただ、

coutent:var(--count);

という指定方法はできません・・・・😢😢😢

後ほど解説しますが、一部CSS変数が使用できない箇所があります。

そのため、--countcounterの値となるようにし、アニメーションでカウントアップするようにします。

(上記ではサンプルとして何回も繰り返しアニメーションされるようにしています。

実際のアニメーション開始タイミングはJavaScriptを用いるなどして調節してください。)

SCSS変数とCSS変数の使い分け

このように非常に便利なCSS変数。

もしかしてSCSS変数の完全上位互換?もうCSS変数だけで良い?

いえいえ、そんなことはありません。

もちろんCSS変数のみを使って実装することも可能ですが、

使い分けることで、パフォーマンスとメンテナンス性を両立できます。

SCSS変数でしか出来ない機能を使う場合はSCSS変数を使用する

SCSS変数には、CSS変数にはない固有の機能があります。

  • 配列
  • マップ(JavaScriptにおけるオブジェクトのようなもの)

これらはCSS変数ではどう頑張っても出来ないので、SCSS変数を使います。

固定値はSCSS変数を使用する

例えば、ダークモードとかを一切実装しない想定の案件で、下記のようにCSS変数のみで実装されていたらどうでしょうか?

.header{
  color: var(--color-1);
  background-color: var(--color-2);
  height: var(--length-1);
}

ここまで読み進められた方は

colorとかbackground-colorとか、なんかこのあと変更予定ありそうな実装やな」

「あれ?JavaScriptで値取得するん?」

ってなったかと思います。

そう、

  • 変更する予定がなく、JavaScriptで取得する予定のない値はSCSS変数
  • それ以外の値はCSS変数

と使い分けることで、

  • どの値が変更される可能性があるのか
  • どの値がJavaScriptで読み取られる可能性があるのか

が分かりやすくなります。

SCSS変数でしか指定できない値はSCSS変数で指定する

CSS変数は様々な箇所で使えますが、使用できない箇所もあります。

  • メディアクエリの値
  • セレクタ名
  • @keyframes
  • url()の画像パス

これらはCSS変数では指定出来ないので、SCSS変数を使いましょう。

 

とはいえ、例えばブレークポイントの値をJavaScriptで使用したい場合、

メディアクエリをCSS変数で指定できないという点が不便になることも(私はつい最近経験しました)。

こういう場合は、SCSS変数とCSS変数で同じ値が設定されるようにしてしまいましょう。

See the Pen Untitled by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

フロントエンド
エンジニア

T.K

初めて「メディアクエリの値をCSS変数で指定できない」と知ったときは頭を抱えましたが、
その後上記の解決方法を思いついたときは、それはもう脳汁出ましたね♨

(CSS変数は若干記述量が多いので、基本的にSCSS変数を使用する)

SCSS変数は下記のようにシンプルに書けます。

$color-1: red;
$length-1: 100;
.hoge{
  color: $color-1;
  width: #{$length-1 * 2px};
}

一方、CSS変数は記述量がちょっとだけ多いので、作業工数(と作業者の精神的疲労)が若干増えます。

:root{
  --color-1: red;
  --length-1: 100;
}

.hoge{
  color: var(--color-1);
  width: calc(var(--length-1)*2px);
}

微々たる差とはいえ、古より「塵も積もれば山となる」と申します。

基本はSCSS変数を使用し、必要なところのみCSS変数を使用する」とすることで、最低限の負担でコーディングが可能です。

やっぱなんでも楽に実装したいですよね♨♨♨

フロントエンド
エンジニア

T.K

私は未だに「JavaScriptのDOM操作、jQuery並にコード量少なくならんかなぁ」とずっと思ってます(小声)。

おわりに

以上、便利なCSS関数の使用方法を紹介してきました。

この記事を書くにあたっていろいろ調べましたが

私自身思いつかない用法があって勉強になりました。

CSS関数を知らなかった方は「なるほど、こんなんあるんや~」、

知ってた方は「こんな使い方もできるんやなぁ」という気づきになったら嬉しいです。

それでは良きコーディングライフを!

ところで

ロジカルスタジオでは、フロントエンドエンジニアを募集しております。

好奇心と技術力にあふれるあなた!下記リンクからお待ちしているしゅこよ