メインコンテンツまでスキップ

えっ!?まだ色の指定でrgba()関数を使っているの!?

CSS

最近次のようなポストをしましたが、主に不透明度を伴う色の指定に現在でもrgba()関数を使用している方が多い印象です。

ポストを別枠で表示する

今年に投稿されているCSSの技術記事でもrgba()関数を使用したサンプルコードが散見されますが、現在rgba()関数はレガシーな指定とされています

rgba()関数使っている人、全員時代に取り残されています

過去のCSSでは色を指定する方法の一つとしてrgba()関数が使用されてきました。この関数はRGB値とアルファ値(不透明度)を組み合わせて色を表現するために用いられます。

🙅‍♂ Not Recommended
.foo {
background-color: rgba(0, 0, 0, 0.8);
}

しかし、ポストで引用しているMDNの文献にも記載があるように、CSS Color Module Level 4(2022年に草案)の勧告以降はrgba()関数は古い構文という扱いになっており、rgb()関数の互換性のために残されているに過ぎません。

こういった事情からrgba()関数のような古い書き方は避けて、rgb()などの色関数を使用したほうがいいでしょう。

🙆‍♂ Recommended
.foo {
background-color: rgb(0 0 0 / 0.8);
}

rgb()関数のアルファ値の指定は全てのモダンブラウザでほぼ平成の時代からサポートされています。IE亡き今rgb()関数よりもrgba()関数を優先して使うメリットは無いでしょう。

参考:types: <color>: `rgb()` (RGB color model): Alpha parameter | Can I use... Support tables for HTML5, CSS3, etc

同じ理由でhsla()関数も古い構文という扱いなので、hsla()関数を使用している方はhsl()関数に切り替えたほうが良いでしょう。

【追記】rgba()関数はレガシーな構文ではないという指摘について

Xの投稿にて以下のような指摘があったため追記します。

  • CSS Color Module Level 4-5 にてrgba()がエイリアスである記載は存在するが、legacyとされる記述は見当たらない。
  • MDNのrgb()関数の日本語ページには「古い構文:rgba()」の記載が存在するが、英語版には「rgba() syntax」となっていてlegacyの記載は存在しない。

記事投稿の約1ヶ月前にMDNでは『rgba() is not necessarily legacy.』というやり取りがあり、rgba()はレガシーではないとされ、英語版のMDNから該当の記述が削除されました。

実際、CSS Color Module Level 5にて追加された相対カラー構文(relative color syntax)もrgba()をサポートしており、仕様的にはあくまでエイリアスでレガシーではないというのが正しい見解です。この点については訂正が必要でしょう。

それでも次のような理由から僕はrgba()関数の使用を控えるつもりです。

  • CSS Color Module Level 4以降に登場した関数にはhwba()のようなアルファ指定を含めた関数は存在しないため、表記の統一性を考慮するとrgb()を用いたほうが良い。
  • rgb()rgba()が同じ機能を持つことを考えると、敢えてエイリアスであるrgba()を用いるメリットは無い。コードの一貫性を保つためにもrgb()に統一することが望ましい。
  • CSS Color Module Level 4の勧告からレガシーの記述が削除される1ヶ月前まで、MDNでもrgba()がレガシーであるという認識がされていた。現在、日本語版にはその記述が残っているなど、仕様的にはそうではないにしろrgba()が古い記述であるという認識は広く浸透している。このような誤解を招く記述を敢えて選択する必要はない。

カンマ区切りも古い構文なので非推奨

こちらもMDNの文献に記載があるように、rgb()関数の引数をカンマで区切る書き方は歴史的な理由から受け入れられているだけで現在では古い書き方とみなされています。

🙅‍♂ Not Recommended
.bar {
background-color: rgb(0, 0, 0, 0.8);
}

実際、カンマで区切った値が使えるのは古くから存在するrgb()hsl()だけです。CSS Color Module Level 4以降に登場したhwb(), lab(), lch(), oklab(), oklch()といった新しい関数ではカンマ区切りの値は使えません。

また、W3Cが発行しているCSS Color Module Level 4の文献においても次のような記述がされています。

For the color functions introduced in this or subsequent levels, where there is no Web compatibility issue, the legacy color syntax is invalid.

このレベル4以降に導入される色関数にはWeb互換性の課題は無いので、それらにおいては旧来の色構文は妥当でない。

参考:CSS Color Module Level 4 (日本語訳) 4.1.2. 旧来の(カンマで分離された)色関数構文

上記のような理由に加えて、カンマで区切る書き方にもメリットは特にないため、古い構文とされているカンマ区切りは避けてスペースで区切る書き方に統一したほうが良いでしょう。

🙆‍♂ Recommended
.bar {
background-color: rgb(0 0 0 / 0.8);
}

最新版のStylelintであればデフォルトで警告が表示される

最新版のStylelintのバージョンを使用している場合はcolor-function-notationの値がデフォルトでmodernとなっているため、カンマで区切った値を使用した場合は怒られるようになっており、ついでにrgba()hsla()rgb()およびhsl()に置き換えられます。

参考:color-function-notation | Stylelint

ただし、Sassを使用しているプロジェクトでは、Sassには独自のrgba()関数が存在するため、Stylelintのルールと衝突する可能性があります。もしもSassの関数を使用していてStylelintの警告が出る場合は、color-function-notationの値をlegacyに設定することで警告を回避できるようです。

不透明度を伴う色の指定はcolor-mix()関数を使うのも便利

不透明度を伴う色の指定はrgb()関数にアルファ値を指定して使うのが良いとお伝えしましたが、iOS 16.2以上をサポートしているプロジェクトであればCSS Color Module Level 5で新しく登場したcolor-mix()関数を使用するのもオススメです。

rgb()とcolor-mix()の比較
.baz {
background-color: rgb(0 0 0 / 0.8);
}
/* color-mix()で書き換えるとこう */
.baz {
background-color: color-mix(in srgb, #000 80%, transparent);
}

おいおい記述量増えてるじゃねーかと思われる方もいると思います。確かにrgb(0 0 0 / 0.8)rgb(255 255 255 / 0.9)のような単純な色の指定であればcolor-mix()を使うメリットは少ないでしょう。

しかし、プロジェクトでテーマカラーのHEX値をカスタムプロパティで定義している場合にcolor-mix()関数の真価を発揮します。

:root {
--color-primary: #e4a153;
--color-secondary: #009f9d;
}

多くの技術記事では、カスタムプロパティで定義したHEX値の色をrgb()関数で使用する際、HEX値をRGB値に変換したカスタムプロパティを追加で用意する方法が紹介されています。

rgb()を使用した場合
:root {
--color-primary: #e4a153;
--color-primary-rgb: 228 161 83;
--color-secondary: #009f9d;
--color-secondary-rgb: 0 159 157;
}
.button[data-type='primary'] {
background-color: rgb(var(--color-primary-rgb) / 0.8);
}
.button[data-type='secondary'] {
background-color: rgb(var(--color-secondary-rgb) / 0.8);
}

しかし、この方法はHEX値をRGB値に変換するための手間が生じ、同じ色を表すカスタムプロパティが複数存在するためあまりスマートな方法では無いように感じます。

一方、color-mix()関数を使えばHEX値を他の値に変換する必要がなく、シンプルにカスタムプロパティを使用できます。

color-mix()を使用した場合
:root {
--color-primary: #e4a153;
--color-primary-rgb: 228 161 83;
--color-secondary: #009f9d;
--color-secondary-rgb: 0 159 157;
}
.button[data-type='primary'] {
background-color: color-mix(in srgb, var(--color-primary) 80%, transparent);
}
.button[data-type='secondary'] {
background-color: color-mix(in srgb, var(--color-secondary) 80%, transparent);
}

また、使う場面は限られますが、現在のテキストカラー(currentcolor)に不透明度を指定することもできます。

currentcolorに不透明度を指定
.button {
color: var(--color-primary);
border: 1px solid color-mix(in srgb, currentcolor 20%, transparent);
}

他にもホバー等の状態変化で色にコントラストをつけたり、簡易的なカラーパレットを作成する場合にもcolor-mix()関数は何かと役立つ印象です。

カラーパレットの例

See the Pen by tak-dcxi (@tak-dcxi) on CodePen.

color-mix()関数は現在全てのモダンブラウザでサポートされていますが、先述したようにiOS SafariはiOS 16.2からのサポートとなります。

参考:color-mix | Can I use... Support tables for HTML5, CSS3, etc

参考リンク