5 ポイント 投稿者 GN⁺ 2025-09-09 | 2件のコメント | WhatsAppで共有
  • Apple が 2025 年の WWDC で公開した Liquid Glass 効果を、ウェブ上で CSS と SVG、物理ベースの屈折計算によって再現する方法を紹介
  • 屈折現象の原理と Snell の法則を用いた ガラス表面の描写および屈折シミュレーションの過程を説明
  • SVG displacement map を使ってレンダリングに適した 変位ベクトル場を生成し、実際の UI コンポーネントに適用できることを実演
  • Chrome に限って SVG filter を backdrop-filter として利用でき、さまざまな **UI 要素(虫眼鏡、スイッチ、プレーヤーなど)**に適用する例を提示
  • リアルタイム効果の実装は可能だが、クロスブラウザの問題やパフォーマンス上の制約があり、今後オープンソース化の計画があることにも言及

紹介

Apple は 2025 年 6 月の WWDC で Liquid Glass 効果を初めて披露した。この効果は、インターフェース要素が曲面の屈折ガラスのように見えるようにし、実際のガラス表面に近い視覚体験を提供する。この記事では、ウェブ環境で CSS、SVG displacement map、物理ベースの屈折計算を通じて、似た効果を作る実践を扱う。完全な実装を目指すのではなく、屈折や反射ハイライトなど主要な特徴を再現した拡張可能な概念実証を目標としている。光が異なる材質を通過するときにどのように屈折するのかという基礎原理から始め、段階的に効果を構築していく。最後に提供されるインタラクティブなデモは、現時点では Chrome でのみ正常に動作する。

屈折現象の理解

屈折とは、光がある材質から別の材質へ移動するときに進行方向が変わる現象を指す。材質ごとに光の速度が異なるために発生し、Snell の法則によって入射角と屈折角の関係が式で表される:

  • n1 * sin(θ1) = n2 * sin(θ2)
    • n1: 最初の媒質の屈折率
    • θ1: 入射角
    • n2: 2 番目の媒質の屈折率
    • θ2: 屈折角

インタラクティブな図で確認できること:

  • 2 つの媒質の屈折率が同じなら、光は屈折せず直進する
  • 2 番目の媒質の屈折率がより高い場合、光は法線方向へ屈折する
  • 2 番目の媒質の屈折率がより低い場合、光は法線から遠ざかり、場合によっては全反射が発生する
  • 入射光が表面に垂直であれば、屈折率に関係なく直進する

このプロジェクトの制約

複雑さを抑え、アルゴリズムを単純化するために次の条件を設定している:

  • 外部媒質の屈折率は 1(空気)
  • 内部のガラス材質には 1.5 を使用(一般的なガラス)
  • 屈折イベントは 1 回のみ考慮(出口での屈折は無視)
  • 入射光は常に背景面に垂直
  • すべてのオブジェクトは 2D 図形で、円形のみを使用(長方形などへ拡張は可能だが計算が必要)
  • オブジェクトと背景面の間に隙間はない
  • これらの条件により、Snell の法則ですべての光線を単純に計算できる
広告

ガラス表面を作る

Liquid Glass 効果を実装するには、仮想ガラスの断面(レンズまたは曲面パネル)を数学関数として定義する必要がある。

表面関数

ガラス表面は surface function で定義され、端から平坦な内部までの厚みを表す

  • 関数入力値 0: 外周、1: ベゼル端(平面の開始)
  • 各点の厚みから導関数を用いて表面の法線ベクトルを求める
const height = f(distanceFromSide);
const delta = 0.001;
const y1 = f(distanceFromSide - delta);
const y2 = f(distanceFromSide + delta);
const derivative = (y2 - y1) / (2 * delta);
const normal = { x: -derivative, y: 1 };

主な表面関数の種類

  • Convex Circle: y = sqrt((1 - (1 - x))^2)
    • 単純な円弧形で、内側に向かうほど急激に平坦になり、屈折の縁がはっきり出る
  • Convex Squircle: y = ((1 - (1 - x))^4)^(1/4)
    • Apple が好んで使う形状で、曲線と平面の境界が滑らかで、拡張しても効果が自然
  • Concave: y = 1 - Convex(x)
    • 凹形(凸の反対)で、光がオブジェクト境界の外側へ屈折するため、外側サンプリングが必要
  • Lip: y = mix(Convex(x), Concave(x), Smootherstep(x))
    • 端に張り出したリップと、中央の浅いくぼみを持つ複合構造
広告

この 4 種類の関数だけでも、表面形状による屈折の違いを効果的に比較できる。

シミュレーション

各表面関数に応じて光線の屈折経路をシミュレーションし、実際の効果の違いを可視化する。

  • 凸形(Convex)は光の経路を内側へ集め、凹形(Concave)は外側へ押し出す
  • Apple の Liquid Glass はほとんどの場合、凸形を好む(Switch などは例外)
  • 背景の矢印は屈折量(変位)を大きさで色分けして表示する
  • 左右の境界で同じ距離にある点は同一の変位を持つため、効率的に再利用できる

変位ベクトル場の生成

ガラス表面全体について、各位置ごとの光の変位方向と大きさを表すベクトル場を構築する

  • 円形では、境界を基準として常に法線方向へ移動する

変位量の事前計算

  • 変位量は境界からの距離ごとに対称なので、半径単位であらかじめ値を計算して配列に保存
  • 2D で 1 回だけ(127 本の光線シミュレーション)計算し、その後 z 軸を中心に回転させて全体の場を生成

ベクトルの正規化

ベクトルを displacement map に使うため、**正規化(最大 1.0 スケール)**を行う

  • 最大変位値を基準に、残りのベクトルの大きさを割って正規化する
const maximumDisplacement = Math.max(...displacementMagnitudes);
displacementVector_normalized = {
  angle: normalAtBorder,
  magnitude: magnitude / maximumDisplacement,
};

SVG displacement map で実際のピクセル単位に変換するときは、scale で再び最大変位値を掛けて元の大きさを復元する。

広告

SVG Displacement Map

数学的な屈折計算の結果を実際にブラウザのレンダリングへ適用するために SVG displacement map を使う

  • <feDisplacementMap /> の各チャンネル(RGBA、8 ビット)は、それぞれ変位の X 軸、Y 軸を担当できる
  • 各チャンネルは 0〜255 の値を持ち、128 が中立(変位なし)を意味する
  • displacement map は必ず画像に変換する必要がある
<svg colorInterpolationFilters="sRGB">
  <filter id={id}>
    <feImage
      href={displacementMapDataUrl}
      x={0}
      y={0}
      width={width}
      height={height}
      result="displacement_map"
    />
    <feDisplacementMap
      in="SourceGraphic"
      in2="displacement_map"
      scale={scale}
      xChannelSelector="R"
      yChannelSelector="G"
    />
  </filter>
</svg>

Scale

Red(X) と Green(Y) チャンネルの値を [−1, 1] の範囲にマッピングする

  • scale 属性でピクセル単位の最大変位量を掛け、実際のレンダリングを実現する
  • scale をアニメーションさせることで、効果の強さを調整できる

ベクトル → Red/Green 値変換

  • 変位ベクトル(角度、大きさ)を x, y の直交座標へ変換した後、128(中立)基準で 0〜255 にマッピングする
const x = Math.cos(angle) * magnitude;
const y = Math.sin(angle) * magnitude;
const result = {
  r: 128 + x * 127,
  g: 128 + y * 127,
  b: 128,
  a: 255,
};

完成した画像は SVG filter の displacement map として利用できる。

Playground

インタラクティブな Playground では、表面形状、ベゼル厚、ガラス厚、effect scale などをリアルタイムで変更しながら、屈折場、displacement map、最終レンダリングの変化を体験できる。

広告

Specular Highlight

最後に specular highlight(ガラス表面の明るいエッジハイライト)を追加する

  • Apple の実装は rim light(縁のライト)方式で、表面法線と光源角度に応じて明るさの強度が変わる

屈折と Specular Highlight の結合

最終的な SVG filter では、displacement mapspecular highlight 画像をそれぞれ <feImage /> で読み込み、<feBlend /> で合成して最終効果を生成する

  • filter パラメータを調整することで、さまざまなビジュアルを演出できる

SVG filter を backdrop-filter として使う

  • 実際に UI コンポーネントへ Liquid Glass 効果を適用するには、Chrome の backdrop-filter: url(#...) サポートが必要
  • backdrop-filter の画像サイズは自動では合わないため、element サイズに合った displacement map を用意する必要がある
.glass-panel {
  backdrop-filter: url(#liquidGlassFilterId);
}

実際の UI コンポーネントへの適用

計算した refraction と displacement map をもとに、現実的な UI コンポーネントへ適用する例を実装

  • Chrome だけが SVG filter を backdrop-filter として処理できる
  • これらの例は本番用の実コンポーネントではなく、さまざまな UI に Liquid Glass 効果が適用される様子を示すことが目的

Magnifying Glass

  • 両側に refraction と zoom、2 つの displacement map を使用
  • 影やスケール調整によってインタラクティブな効果を付与
  • ドラッグでレンズを変形させ、屈折経路を観察できる
  • 滑らかな specular highlight を追加
広告

Searchbox

  • 標準的な入力欄の形に Liquid Glass 効果を適用

Switch

  • lip bezel を使い、外側は凸、内側は凹
  • 中央のスライダーだけが拡大・縮小された状態で、端では内部画像の屈折を適用

Slider

  • convex bezel を使い、現在値をガラス越しにそのまま表示し、両側には背景の屈折を適用

Music Player

  • Apple Music の Liquid Glass panel スタイルを模倣

  • convex bezel と subtle specular highlight により立体感を付与

  • iTunes Search API を使ってアルバムアートや曲名などの情報を読み込む

  • (リスト形式の曲名およびアルバム情報を提供)

結論

このプロトタイプは、Apple の Liquid Glass 概念をリアルタイム屈折効果と簡易的なハイライトによって単純化して表現したものだ。Chromium ベースのブラウザ(または Electron)でのみ実用的に動作し、他のブラウザでは blur レイヤーで代替できる。
これは実験的な実装であり、shape/size の変化ごとに displacement map を再生成するのは非常に非効率的である(filter の scale など一部のパラメータのみアニメーション可能)。
今後のオープンソース公開を検討しており、最適化やコード整理にも関心があると述べている。

2件のコメント

 
bobross0 2025-09-16

ウェブで見たリキッドグラスの中で、最も近い感じですね。

 
GN⁺ 2025-09-09
Hacker Newsの意見
  • WebGLシェーダーで似た機能を作ったことがあり、複数のブラウザで動く利点があるとして、https://real-glass.vercel.app を共有していた。難しかったのは、実際のHTML要素の背後で屈折効果を正しく再現する部分だったということ
    • ガラス効果をテキストの上に重ねて動かしたときに生じるゴースト現象や遅延は、何が原因なのか気になる
    • とてもすごいと思う。端で色が分離する分散効果まで実装されているように見える
    • ビジュアルはすばらしいが、実際に使うには反応速度が遅すぎる。元の投稿者のもののほうがはるかに滑らかに動く
    • 印象的だ
  • スクロールするたびにM4-Max Macbook Proでも引っかかるのが印象的だった。もしUI全体にこうした技術が適用されるなら、性能面で不安が先に立つ。Appleで可能なのは極度に最適化しているからだろう
    • 本文の執筆者として、性能問題は先に直そうとしていたが、予想より早く誰かがHNに投稿してしまった。指摘はその通りで、今はやや遅く、さらなる最適化が必要だ。屈折や変位マップだけでなく、可視化などほかの部分もまだ最適化できていない
    • Chromeで性能改善を急いで進めたので、少しは良くなっているはずだ。SafariではSVGレンダリングが依然として遅い。思いがけず投稿されてしまい、まだ改善の余地が残っている
    • このサイトはスクロールが滑らかではない。たいていの場合、CSSはGPUをうまく活用できない。AppleはUI処理のためにシリコンへ特別な処理を追加しているように見える
    • 私の環境でも同じで、縁の効果もきちんと見えなかった
  • 内容もよいが、記事全体の構成とクオリティもすばらしかった。Liquid glassという概念そのものは実際のUXに特別な追加価値を与えるわけではなく、むしろやりすぎるとUXを損なうこともあるが、新鮮で楽しい体験ではある
  • Chrome専用デモであることを強調し、最後のインタラクティブデモはChromeでのみ動作する(SVG filterによるbackdrop-filterの制約のため)と書かれていた。他ブラウザでも本文の閲覧や簡単なシミュレーションは可能とのこと。これに対して「お前の一族みんなに不名誉あれ!」というユーモラスな反応があった
    • こういうやり方が許されるのはやむを得ない。その機能が特定のブラウザでしかサポートされていないことを示すのが目的なのだから
    • 面白いことに、私の場合はChromeのほうがページが遅く、スクロールもより引っかかる一方で、Firefoxではその効果はサポートされていないにもかかわらず、むしろより滑らかだった。それでも記事自体には非常に感心した
    • 私も似た反応だったが、不思議なことにFireFoxでもかなりよく見えた
    • 参考を知りたいなら、https://youtu.be/GamP4chXJ2I?t=17 を見るとよい
  • liquid glassデザイン言語がWebに適用されるのは予想通りだった。しかし、テキストの歪みのせいでWebサイトが私のバッテリーを食いつぶすなら、長居するつもりはない。すでに多くの人が引っかかりを指摘しているので、これ以上は触れない
  • すばらしく、手間のかかった仕事だ。しかしliquid glassというのは、近接する要素同士がメタボールのように結合したり、さまざまなティント/クリアモードがあったり、コントロールがコンテンツと分離したレイヤーに置かれていたりするなど、デザイン言語全体を意味する。今回の実装は、いわば単なる「ガラスシェーダー」に近い
    • 要素の結合は、もっと単純なフィルターである「Goo」フィルターで解決できる。以前から使われている方法だ。参考実装: https://codepen.io/lenymo/pen/pJzWVy
  • liquid-glass用JSライブラリをフォークして位置修正パッチを追加した。プレゼンで使うと面白い。ソースコード: https://github.com/nkzw-tech/liquid-glass
    • いいね。むしろこちらのほうが気に入った
  • Firefoxでは一部の効果しか動かないが(その代わり性能は確保できる)、これまで見た中では最高の実装だと思う。ここ数日かなり関連リサーチをしていたので、なおさら印象的だった。特に気に入ったのは、Webサイトのデザインと丁寧に作り込まれたインタラクティブな可視化だった。Bartosz CiechanowskiやJosh Comeauの作品と同格だと感じた。ソースコードが公開されることを願う
  • ブラウザ対応の制約にもかかわらず、すばらしい試みだと思う。インラインのインタラクティブな例が付加価値を与えていた。ある瞬間、Ciechanowskiの記事を読んでいるような感覚になった(参考: https://ciechanow.ski/)
  • 新しく登場したray-tracedスクロールバーやボタンが、実際により機能的で、昔のテキストモードのTurbo VisionやWindows 3のボタンより生産性を高めるのか気になる