【CSS】独自プロパティを作る CSS Properties and Values API (Houdini)

CSS といえばブラウザーが用意したプロパティを使って書くものですが、W3C で策定している「CSS Properties and Values API」を使うことで、独自の CSS プロパティを作ることができます。今回はこの CSS Properties and Values API について詳しく解説します。

CSS Properties and Values API とは

CSS Properties and Values API は、新たな CSS プロパティを登録する API のことです。API ですから、JavaScript を通して独自の CSS プロパティを登録することにができますが、もちろん、CSS で静的に記述して登録することも可能です。

ここまで聞くと、自由にスタイリングに影響できる CSS プロパティを自作できるかのように期待してしまうかもしれませんが、残念ながらそうではありません。

以前、このブログで CSS 変数 (CSS カスタムプロパティ) について解説しましたが、この CSS 変数も一見独自の CSS プロパティを扱っているように見えます。もちろん、そのようなことはなく、単なる変数でしかありません。

/* CSS 変数 (CSS カスタムプロパティ) の定義の例 */
:root {
  --main-color: #06c;
}

実は、CSS Properties and Values API は、この CSS 変数 (CSS カスタムプロパティ) の仕組みを拡張したものです。CSS 変数の正式な名称は「カスタムプロパティ」です。一方、CSS Properties and Values API で定義できる独自の CSS プロパティは「登録済みカスタムプロパティ (registered custom property)」と呼びます。この名称の通り、違いは登録済みかそうでないかだけです。

本来の CSS プロパティは、値の型、継承の有無、初期値というものを備えています。ところが CSS 変数では、値に型はなく、継承なしという選択はできません。そして、初期値の定義はできません。つまり CSS 変数は CSS プロパティとしてはかなり情報不足になります。情報不足ということは、CSS 変数の値をうまく展開できない状況があり得るということです。

登録済みカスタムプロパティは、CSS 変数に足りない部分を補う形で、本来の CSS プロパティに近い値の定義を実現します。CSS 変数に足りないものとは、前述の通り、値の型の定義、継承の有無、初期値です。これらを事前に登録することになります。

CSS Properties and Values API は独自の CSS プロパティを作れるわけですが、一般的な CSS プロパティのようにスタイリングに直接作用させることはできません。あくまでも CSS 変数の延長です。そういう意味では、登録済み CSS プロパティは「登録済み CSS 変数」と呼ぶほうが実態に合っているかもしれませんね。値の型の定義、継承の有無、初期値が事前に登録できると何がうれしいのかについては後述します。

なお、当ブログで Houdini の概要を紹介しましたが、この CSS Properties and Values API は Houdini ファミリーの一つです。そして、Houdini の目玉ともいえる CSS Painting API や CSS Layout API の礎となる API です。

CSS 変数でできないこと

ここでは、CSS 変数の限界を見てみましょう。言い換えると、CSS 変数では実現できないけれども、登録済みカスタムプロパティなら実現できるケースを見ていきます。

次の例は、ボタンの背景色を CSS 変数 --btn-color を使って赤色にしています。そして、transition プロパティを使って、マウスポインターを乗せると 1 秒かけて緑色にしようとしています。

<button>送信</button>

<style>
  button {
    --btn-color: red;
    background-color: var(--btn-color);
    transition: --btn-color 1s;
  }

  button:hover {
    --btn-color: green;
  }
</style>

残念ながらこのサンプルは期待通りに transition が機能しません。マウスポインターをボタンに乗せたら即座に緑色に変化してしまいます。なぜなら、transition プロパティの値に指定した CSS 変数名 --btn-color に問題があるからです。

CSS 変数には型という概念がありません。ここで言う型とは、寸法(3em や 100px など)、色(#ff0000 や red など)、パーセンテージ(10%)などを指します。transition プロパティに --btn-color を指定しても、ブラウザーはそれがどんな型を持っているのかを知りません。私たちはそれが色であることは知っていますが、何も知らないブラウザーは transition で何を変化させればよいか分からないのです。

CSS Properties and Values API で規定された方法で CSS 変数に型を登録してあげれば、この問題が解決します。

JavaScript によるカスタムプロパティの登録

まずは CSS プロパティの登録の方法を見てみましょう。JavaScript でカスタムプロパティを登録するには CSS.registerProperty() メソッドを使います。

<script>
  CSS.registerProperty({
    name: '--btn-color',
    syntax: '<color>',
    inherits: false,
    initialValue: 'blue',
  });
</script>

前述のサンプルに上記の script 要素を追加すれば、transition が期待通りに動作します。

CSS.registerProperty() メソッドには次のプロパティを持ったオブジェクトを指定します。

メンバー名必須説明
name必須Stringカスタムプロパティの名前を指定します。
syntax任意String型を指定します。デフォルトは "*" です。指定可能な値は後述します。
inherits必須Boolean継承するかどうかを指定します。
initialValue任意String初期値を指定します。

指定可能な syntax の値

CSS.registerProperty() メソッドの引数に指定する syntax には次の値が用意されています。

説明値の例
<length>長さを表します1em, 20px
<number>実数を表します1.5
<percentage>パーセンテージを表します100%
<length-percentage>長さ、または、パーセンテージを表します130px, 50%
<color>色を表しますred, #ff0000
<image>画像の URL、または、グラデーションを表しますurl(“http://example.jp/bg.jpg”), linear-gradient(white, gray)
<url>URL を表しますurl(“http://example.jp/bg.jpg”)
<integer>整数を表します1, -2
<angle>角度を表します90deg, 3rad
<time>時間を表します10s, 500ms
<resolution>解像度を表します90dpi
<transform-function>変形関数を表しますscale(2), rotate(90deg)

syntax のリスト表現と「または」表現

以上は単独の値を指定する場合の型を表しますが、CSS プロパティによっては複数の値をリスト形式で指定するものがあります。さらに、リストの各々の値をスペースで区切る場合とカンマで区切る場合があります。syntax ではこういったリスト表現にも対応しています。

margin プロパティでは 10px 25px 15px 25px のように値を指定できますが、このようなスペース区切りの長さをリストを表したい場合は "<length>+" のように + を付けます。

background-image プロパティでは url(a.gif), url(b.gif) のように値を指定できますが、このようなカンマ区切りの URL のリストを表したい場合は "<url>#" のように # を付けます。

さらに syntax は「または」という表現が可能です。"<length> | auto" のように | で区切ると、10em100px といった長さを表す値、または、"auto" という固定値のいずれかが指定できるプロパティになります。

CSS によるカスタムプロパティの登録

カスタムプロパティの登録は JavaScript からだけではなく CSS で記述することも可能です。登録には @property ルールを使います。前述のサンプルを CSS だけで記述すると次のようになります。

<button>送信</button>

<style>
  @property --btn-color {
    syntax: "<color>";
    inherits: false;
    initial-value: blue;
  }

  button {
    --btn-color: red;
    background-color: var(--btn-color);
    transition: --btn-color 1s;
  }

  button:hover {
    --btn-color: green;
  }
</style>

ブラウザーのサポート状況

2022 年2 月現在、CSS Properties and Values API をサポートしているブラウザーは Chrome や Edge などの Chromium ベースのブラウザーのみです。

まとめ

Properties and Values API では、CSS 変数に型を与えることができると覚えていただければ、おおむね合っていると思います。Properties and Values API 単独ではありがたみを感じることは少ないでしょうが、Houdini のメインディッシュでもある CSS Painting API を使いこなすには、必要な API でもあります。CSS Painting API については、別途記事にしようと思っています。

今回は以上で終わりです。最後まで読んでくださりありがとうございました。それでは次回の記事までごきげんよう。

Share