CSSのbackdrop-filterですりガラス風の背景を作る

​​CSS​HTML,Playwright

すりガラスのように後ろがぼけて透ける背景は、要素の背景色を半透明にし、backdrop-filter: blur() で後ろをぼかすと作れます。背景色が不透明だと、ぼかしは見えません。また、すりガラスのヘッダーの中にすりガラスのメニューを入れると、メニューだけぼけなくなります。これは、ヘッダーのぼかしを ::before に移すと直ります。

補足

検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。HTML と CSS だけのページを Playwright で開き、要素の内側をスクリーンショットに撮って、画素の明るさのばらつき(標準偏差)や彩度を計算しました。ばらつきが小さいほど、後ろの模様がぼけていることになります。Firefox と Safari は試していません。

縦じまと水色・ピンクの円の上に、カードを重ねた画面を3つ縦に並べたもの。上は半透明の白だけで、後ろの縞と文字がそのまま透けて、カードの文字と重なって読みにくい。中は半透明の白に blur(12px) を足したもので、後ろがぼけて灰色がかった面になり、カードの文字が読める。下は不透明な白に blur(12px) を付けたもので、ただの白いカードになっている
同じ背景の上に、3通りのカードを重ねたところ。すりガラスに見えるのは真ん中だけ

半透明の背景色と backdrop-filter を組み合わせる

すりガラスのカードの CSS は次のとおりです。

css
.glass {
  background-color: rgb(255 255 255 / 0.3); /* 半透明の白 */
  -webkit-backdrop-filter: blur(12px); /* Safari 17 以前向け */
  backdrop-filter: blur(12px); /* 背後をぼかす */
  border: 1px solid rgb(255 255 255 / 0.5);
  border-radius: 16px;
}

backdrop-filter は、要素の後ろにあるものに、ぼかしや色の変化をかけるプロパティです。要素そのものではなく、要素を通して見える後ろの部分が変わります。ぼかしには blur() を使います。

細かい縦じまと色の円を描いた背景の上に、このカードを置いて測りました。カードの内側の明るさの標準偏差は、半透明の白だけのときが 61.8、blur(12px) を足すと 17.6 でした。縞の白と黒の差がならされ、後ろがぼけた面になっています。

背景色を付けずに backdrop-filter だけを付けても、ぼかしはかかりました(標準偏差 25.0)。ただし、明るさの平均は 165.9 で、半透明の白を重ねたとき(192.2)より暗くなりました。半透明の白は、後ろを明るく見せる役目をしています。

背景色が不透明だと、ぼかしは見えない

背景色を不透明な白(#fff)にしたカードに blur(12px) を付け、付けないカードと画素を比べました。カードの内側の 104,000 個の値(縦横の画素数 × RGBA の4つ)は、1つも違いませんでした。

MDN の backdrop-filter のページにも、要素か、その背景が透明か半透明である必要があると書かれています。後ろがぼけないときは、まず背景色の透明度を確かめてください。

blur の値は、後ろの模様の大きさで決める

blur() の値を 0px から 32px まで変えて、カードの内側の縞の残り方を測りました。後ろは縞だけにして、細かい縞(12px ごとに繰り返す)と粗い縞(48px ごと)の2通りで試しています。

blur() の値を横軸、ガラスの内側の明るさの標準偏差を縦軸にした折れ線グラフ。細かい縞の線(灰色)は 4px でほぼ 0 まで下がる。粗い縞の線(水色)はゆっくり下がり、blur(12px) の点(ピンク)で 22.4、32px で 6.2
blur() の値と、ガラスの内側に残る縞の濃さ。細かい縞は 4px でほぼ消え、粗い縞は 12px でもまだ残る

細かい縞は、blur(4px) で標準偏差が 4.1 まで下がり、ほぼ見えなくなりました。粗い縞は、blur(12px) でも 22.4 で、16px で 13.5、24px で 8.0 でした。模様が大きいほど、ぼかすには大きな値が要ります。試したのは縞だけですが、この結果からすると、後ろに大きな写真や太い文字があるなら大きめの値に、細かい模様だけなら小さめの値にすると、ちょうどよくなりそうです。

色を鮮やかに見せたいときは saturate() を足す

ぼかすと、後ろの色が混ざって、くすんで見えやすくなります。色の円がある背景では、カードの内側の彩度の平均が、半透明の白だけのとき 0.170、blur(12px) を足すと 0.161 に下がりました。色を残したいときは、saturate() を空白で区切って続けます。

css
backdrop-filter: blur(12px) saturate(180%);

saturate(180%) を足すと、彩度の平均は 0.226 に上がりました。

すりガラスのヘッダーの中のメニューがぼけないときは ::before に移す

すりガラスのヘッダーの中に、下へはみ出すすりガラスのメニューを入れると、メニューの後ろがぼけません。

css
.bar {
  position: relative;
  height: 48px;
  background-color: rgb(255 255 255 / 0.3);
  backdrop-filter: blur(12px);
}

.menu {
  position: absolute;
  top: 100%;
  left: 40px;
  width: 200px;
  height: 120px;
  background-color: rgb(255 255 255 / 0.3);
  backdrop-filter: blur(12px);
  border-radius: 0 0 12px 12px;
}
縦じまと円の背景の上に、ヘッダーとそこから下に出るメニューを置いた画面を2つ縦に並べたもの。上はヘッダーに backdrop-filter を付けた場合で、メニューの後ろの縞と水色の円がくっきり透けている。下はぼかしを ::before に移した場合で、メニューの後ろもぼけている
ヘッダーに backdrop-filter を付けるとメニューの後ろはぼけない(上)。::before に移すとぼける(下)

メニューのうちヘッダーより下に出た部分を測ると、標準偏差は 44.3 でした。メニューの backdrop-filter を外したときも 44.3 で、明るさと彩度の平均も同じでした。ぼかしがまったく効いていません。

MDN の英語版の backdrop-filter のページにある「Backdrop root」の説明によると、backdrop-filter がぼかすのは、いちばん近い backdrop root の祖先までの範囲です。backdrop-filter、filter、1 より小さい opacity、mask や clip-path、mix-blend-mode などを持つ要素が backdrop root になります。ヘッダーは backdrop-filter を持つので backdrop root になります。そのため、ヘッダーより後ろにあるページの背景は、メニューを通して透けてはいても、ぼかされません。

親に opacity: 0.99 や filter: brightness(1) を付けたときも、中のすりガラスのカードの標準偏差は 62.2 と 61.7 でした。ぼかしのない半透明の白(61.8)とほとんど同じです。見た目がほとんど変わらない値でも、親に付けるとぼかしが効かなくなります。

直すには、ヘッダーのぼかしを ::before に移し、ヘッダーそのものには backdrop-filter を付けないようにします。

css
.bar-fixed {
  position: relative;
  isolation: isolate; /* ::before を、ヘッダーの文字やメニューより下に重ねるため */
  height: 48px;
}

.bar-fixed::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: rgb(255 255 255 / 0.3);
  backdrop-filter: blur(12px);
}

.menu は前のコードのままです。こうすると、メニューの下に出た部分の標準偏差は 5.3 になり、後ろがぼけました。ヘッダーのメニューがない部分も、直す前と同じ 3.6 で、ヘッダーのすりガラスもそのまま残っています。

::before を z-index: -1 で文字の下に置くため、ヘッダーに isolation: isolate を付けて、新しい重ね合わせコンテキストを作っています。これを外すと、ヘッダーのすりガラスが消え、ヘッダーの部分は縞がぼけずに見えました(標準偏差 101.3)。isolation は、MDN に挙がっている backdrop root の条件には入っていません。

Safari 向けに -webkit- 付きも書いておく

MDN の互換性データ(@mdn/browser-compat-data 8.1.8)では、backdrop-filter は Chrome 76、Firefox 103 から使えます。Safari では、接頭辞なしで使えるのが 18 から、-webkit-backdrop-filter なら 9 から使えます。Safari 17 以前にも対応するなら、最初のコードのように両方を書きます。

なお、検証環境の Chromium 153 では、CSS.supports('-webkit-backdrop-filter', 'blur(12px)') は false で、CSS.supports('backdrop-filter', 'blur(12px)') は true でした。Chromium では接頭辞なしの行だけが使われ、両方を書いても問題なくぼけています。

​Posted by 86