CSS の transparent が透明じゃない世界

【追記】2022年3月にリリースされた Safari 15.4 で以下の問題は起きなくなりました。


CSS で色指定をするときに transparent というキーワードが使えますね。

その名のとおり「透明」の指定なんだけど、特定の環境では期待した結果になりません。

これがどう見えるか

この四角い領域の表示は閲覧環境によって変わります。

↓これの左右どっちか。

Mac の Safari では右半分のように黒く濁ったグラデーションになります。黒というか灰色というか。

また iOS, iPadOS だとすべてのブラウザーが右。
Safari だろうが Google Chrome だろうが Firefox だろうが Opera だろうが Microsoft Edge だろうが DuckDuck Go だろうが。

それ以外の環境だと左半分のようにクリアなグラデーションになっているはず。

要するに Apple の息のかかった環境が右で、それ以外が左です。

コードはこう

上記の四角い領域にはこういうスタイルがあててあります。

background: linear-gradient(red, transparent);

red から transparent へのグラデーション。赤から透明に変わっていくんだから上の左側のようになるはずでした。

ところがなぜかアップル環境だと黒い。

どうしてこうなったか

CSS の色指定 transparent キーワードについて W3C のドキュメントではこういうことになってます。

CSS Color Module Level 3

transparent
Fully transparent.

まったくの透明。黒く濁る余地はないはず。

ところがこれには続きがあって

This keyword can be considered a shorthand for transparent black, rgba(0,0,0,0), which is its computed value.

rgba(0, 0, 0, 0) の略記と考えて差し支えない、と。
4番目のアルファチャンネルが 0 だからこれで透明だよね、っていう話ですね。

それは透明じゃない

確かに不透過度が 0 ならまったくの透明になりそうです。

ただそれは transparent を単体で使った場合であって、グラデーションが絡んでくると話が変わってきます。

先ほどの linear-gradient(red, transparent) は上記にならって言い換えると rgba(255, 0, 0, 1) から rgba(0, 0, 0, 0) へのグラデーション。

アルファは 1 から 0 で次第に透明になっていくけど、色は赤から黒に変わっていくことになってしまいます。

これ何か transparent という言葉から想像されるものと違う。それは透明じゃない。

どうすればよかったのか

アップルの transparent は transparent ではないことがわかったので、少なくとも gradient の指定で transparent というキーワードは使わない、というところでしょうか。

赤から透明にしたければ明確に「赤の不透過度 1 から赤の不透過度 0 へ」と書いた方がよさそう。

linear-gradient(rgba(255, 0, 0, 1), rgba(255, 0, 0, 0))

馴染みある16進数表記ならこうですね。

linear-gradient(#ff0000ff, #ff000000)

本当にそんな仕様なのか

話はわかったけど transparent が透明じゃないなんてつらすぎる。CSS って本当にそんな仕様なんでしょうか。

みんな大好き MDN では

<color> – CSS: Cascading Style Sheets | MDN

グラデーションの場合の同様、予期しない動きを避けるために、現在の CSS の仕様書は transparentアルファ乗算色空間で計算するように定めています。しかし、古いブラウザーはアルファ―チャンネルが 0 の値である黒として扱うかもしれません。

はっきり古いと言われてしまっている。

また上記アルファ乗算色空間(alpha-premultiplied color space) からリンクされている W3C のドキュメント(の最新版)で What does “pre-multiplied” mean? の詳細を開くと

CSS Images Module Level 3

if a gradient were to incorrectly transition in non-premultiplied space, the center of the gradient would be a noticeably grayish color

変化の過程でグレーになるのは incorrectly に変化する場合だと。こちらでもはっきり間違いであると言われちゃってます。

よかったこと

これを書いている途中で iOS 15 にアップデートして「これで直ってたらこの記事は無駄になるのか」と思ったんですが、まったく変わってなかったので安心しました。

【追記】15.4 で直ってしまいました。

  • このエントリーをはてなブックマークに追加