CSSのmix-blend-modeで文字色を背景の反転色にする方法

​​CSS​HTML,Playwright,アクセシビリティ

文字の色を白(#fff)にして、mix-blend-mode: difference を指定すると、文字の色が後ろの色を反転した色になります。白い背景の上では黒、黒い背景の上では白で表示されるので、色の違う部分をまたいで動く固定ヘッダーの文字なども、背景に合わせて自動で色が変わります。ただし、後ろの色を塗っている要素の場所によっては反転せず、白い文字のまま見えなくなることがあります。

補足

検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。Playwright で開いたページのスクリーンショットから画素の色を読み取って確かめました。Firefox と Safari、スマートフォンの実機での表示は試していません。各ブラウザーの対応バージョンは、互換性データ(@mdn/browser-compat-data 8.1.8)の値です。

白い文字に mix-blend-mode: difference を指定する

html
<section class="hero">
  <h1 class="title">猫の手 Neko Note</h1>
</section>
css
.hero {
  background: #000;
}

.title {
  color: #fff;
  mix-blend-mode: difference;
}

mix-blend-mode は、要素の内容を、後ろにある内容とどう混ぜ合わせて表示するかを決めるプロパティです。difference は、2つの色の差を表示する値です。Compositing and Blending の仕様では、後ろの色を Cb、要素の色を Cs として、色の成分ごとに | Cb - Cs | を計算すると定められています。白で塗ると後ろの色が反転し、黒で塗ると何も変わらない、とも書かれています。

検証環境で、白い文字の後ろの背景を変えて表示した画面が次の画像です。

4つの枠を縦に並べた画面。同じ白い文字「猫の手 Neko Note」に mix-blend-mode: difference を指定している。白い背景では文字が黒、黒い背景では白、水色の背景ではオレンジがかった赤になり、灰色の背景では文字がほとんど見えない
白い文字に mix-blend-mode: difference を指定し、後ろの背景色を変えて比べた

文字の部分の画素を読み取ると、白い背景の上では #000000、黒い背景の上では #ffffff でした。画像のとおり、漢字やひらがなも英字と同じように反転します。

色が反転するのは、文字の色が白のときだけ

| Cb - Cs | の計算なので、要素の色が白(成分がすべて 255)のときだけ、結果が「255 から後ろの色を引いた色」、つまり反転した色になります。検証環境で、白の代わりに #00c8e8 で塗った箱を mix-blend-mode: difference で重ねると、次のようになりました。

要素の色 後ろの色 重なった部分の色
#00c8e8 #ffffff #ff3717
#00c8e8 #000000 #00c8e8

黒い背景の上では、要素の色がそのまま出ました。背景の色を反転させたいときは、文字の色を #fff にします。

灰色に近い背景では、文字が読めなくなる

反転した色は、後ろの色が中間の明るさに近いほど、後ろの色に近くなります。検証環境で、白い箱を mix-blend-mode: difference で重ね、重なった部分の色と、後ろの色とのコントラスト比を求めました。コントラスト比は、WCAG の式で計算しています。

後ろの色 重なった部分の色 コントラスト比
#ffffff #000000 21:1
#000000 #ffffff 21:1
#eefafd #110502 18.85:1
#1f2a30 #e0d5cf 10.19:1
#00c8e8 #ff3717 1.79:1
#8a8a8a #757575 1.33:1
#808080 #7f7f7f 1.01:1

白や黒に近い背景では十分なコントラストが出ます。一方で、#808080 の上では #7f7f7f になり、先ほどの画像のように文字がほとんど見えなくなりました。水色の #00c8e8 の上でも 1.79:1 です。MDN の色のコントラストのページによると、WCAG の AA の基準では、本文のテキストに 4.5:1、大きいテキストに 3:1 以上のコントラスト比が必要です。中間の明るさの色の上に文字が来るデザインでは、difference だけでは読める色になりません。

文字が白と黒の境目にかかると、1つの文字の中でも、黒い部分の上は白、白い部分の上は黒で表示されました。

2つの枠を縦に並べた画面。上は左半分が黒、右半分が白の背景で、「Neko」の「e」の途中で、文字の色が白から黒に切り替わっている。下は濃い色と薄い色の斜めのしま模様の背景で、文字がしまに沿って薄い色と濃い色に分かれている
背景の色が途中で変わる場所に、mix-blend-mode: difference の白い文字を置いた

固定ヘッダーでは、header 自体に指定する

ページの上に固定したヘッダーの文字を、下を流れる部分の色に合わせて反転させたい、という使い方があります。このとき、position: fixed の要素の中の見出しに mix-blend-mode を指定しても、反転しませんでした。

css
/* 反転しなかった書き方 */
header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
}

header h1 {
  color: #fff;
  mix-blend-mode: difference;
}

mix-blend-mode を、position: fixed を指定した header 自体に移すと、白い部分の上では黒、黒い部分の上では白、水色の部分の上ではオレンジがかった赤で表示されました。

css
/* 反転した書き方 */
header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  mix-blend-mode: difference;
}

header h1 {
  color: #fff;
}
上下2つの組に分けた画面。上の組の「header の中の h1 に mix-blend-mode」では、ページの先頭で白い背景の上の文字が見えず、黒と水色の部分の上では白い文字のまま表示されている。下の組の「header 自体に mix-blend-mode」では、白い部分の上で黒、黒い部分の上で白、水色の部分の上でオレンジがかった赤の文字になっている
固定ヘッダーで mix-blend-mode を指定する要素を変え、スクロールして下の部分の色を変えた

違いが出るのは、重ね合わせコンテキストのためです。仕様の、HTML に固有の動作を定めた節では、混ぜ合わせを指定した要素は、その要素が属する重ね合わせコンテキストの中で、下にある内容と混ぜ合わされる、と定められています。position: fixed の要素は新しい重ね合わせコンテキストを作るので、header の中の h1 は、背景のない header の中だけで混ぜ合わされ、ページの白や黒とは混ざりません。

同じことは、背景のある要素と文字のあいだにある背景のない要素が、重ね合わせコンテキストを作る場合にも起きます。検証環境で、白い背景の section と白い文字のあいだに div を入れ、その div に次の指定をすると、文字はどれも白いままで、見えなくなりました。

  • isolation: isolate
  • opacity: 0.99
  • transform: translateZ(0)
  • position: relative と z-index: 0

position: relative だけで z-index を指定しない div では、文字は黒く反転しました。どれも、MDN の重ね合わせコンテキストのページで、重ね合わせコンテキストを作る条件として挙げられているものです。反転しないときは、mix-blend-mode を指定した要素から背景のある要素までのあいだに、これらの指定がないかを確かめます。

ページの背景色は、html か body に指定しておく

画面が白く見えていても、html と body に背景色を指定していないページでは、白い文字は反転せず、白いまま見えなくなりました。html か body に background: #fff を指定すると、黒く反転しました。

css
body {
  background: #fff;
}

仕様のルート要素のグループの節では、ルート要素のグループ(ページ全体の内容をまとめて混ぜ合わせるグループ)には、ページの背景(キャンバスの背景)が描かれると定められています。その次のルートグループの節によると、ブラウザーが最後に敷く白い面は、このグループの外側のルートグループにあり、白い面を敷くことは必須ではありません。背景色を指定していないページの白は、この外側の面の色なので、文字と混ぜ合わされませんでした。

対応しているブラウザー

互換性データでは、mix-blend-mode(difference の値を含む)に、各ブラウザーが次のバージョンから対応しています。

ブラウザー mix-blend-mode
Chrome 41
Edge 79
Firefox 32
Safari 8
iOS の Safari 8

​Posted by 86