WebGL & CSS — エフェクト検証レポート

WebGL × CSS
ライブラリ比較

水面波紋エフェクトを題材に、JS/WebGL系ライブラリ 3種と CSS 系アプローチを セットアップ・パフォーマンス・カスタマイズ性など多角的に比較します。

Curtains.js PixiJS jQuery Ripples CSS Only
00

ライブ デモ

実装済みの3つのデモを実際に操作できます。マウス / タッチで波紋を起こしてください。

↖ マウスを動かして波紋をインタラクション ↗ 新しいタブで開く
01

ライブラリ概要

各アプローチの技術カテゴリとキースコアを一覧します。

Curtains.js
WebGL DOM Wrapper
セットアップ
2/5
カスタマイズ
5/5
パフォーマンス
4/5
DOM 統合
5/5
PixiJS
2D Rendering Engine
セットアップ
3/5
カスタマイズ
4/5
パフォーマンス
5/5
DOM 統合
2/5
jQuery Ripples
jQuery Plugin (WebGL)
セットアップ
5/5
カスタマイズ
2/5
パフォーマンス
3/5
DOM 統合
4/5
CSS Only
CSS Anim / SVG Filter
セットアップ
4/5
カスタマイズ
3/5
パフォーマンス
2/5
DOM 統合
5/5
02

多角的比較マトリックス

比較軸 Curtains.js PixiJS jQuery Ripples CSS Only
技術基盤 WebGL + GLSL WebGL2 / Canvas WebGL (抽象化) CSS / SVG Filter
セットアップ難易度
GLSL シェーダー制御 ✓ フル制御 △ Filter 経由 ✗ 非対応 ✗ 非対応
インタラクション Mouse / Touch Mouse / Touch (Pointer) Mouse / Touch Hover / Focus のみ
タッチ対応 △ Hover 不可
依存ライブラリ curtainsjs のみ pixi.js のみ jQuery + plugin 不要
バンドルサイズ (gzip 目安) ~60 KB ~470 KB v8: tree-shaking可 ~90 KB (jQuery 込) 0 KB
DOM 要素へのマッピング ✓ 完全対応 ✗ Canvas 独立 ✓ bg-image ✓ 完全対応
GPU アクセラレーション ✓ WebGL ✓ WebGL2 △ 解像度依存 △ 一部のみ
SSR / 静的サイト
メンテナンス状況 停止 最終 2024年 活発 v8.18.1 / 2026.04 停止 最終 2020年 ブラウザ標準 対応率 92%
学習コスト 高 (GLSL 必須) 中〜高 低〜中
03

JS ライブラリ 詳細

◆ WebGL DOM Wrapper

Curtains.js

DOM 要素(img / video)を WebGL のプレーンにマッピングし、カスタム GLSL シェーダーで加工できるライブラリ。 波紋マップを 2D Canvas で動的生成し、フラグメントシェーダーで UV 座標を歪めることで水面効果を実装。 DOM レイアウトとの同期が完全なため、スクロール・リサイズへの追従も容易。

Fragment Shader — ノーマルマップによる歪み
// 波紋を UV 座標の歪みとして描画するフラグメントシェーダー
precision mediump float;
varying  vec2 vTextureCoord;
uniform sampler2D uTexture;       // 元画像テクスチャ
uniform sampler2D uDisplacement;  // 2D Canvas で生成した波紋マップ

void main() {
  vec4 disp       = texture2D(uDisplacement, vTextureCoord);
  vec2 distortion = (disp.rg - 0.5) * 2.0; // [0,1] → [-1,1]
  vec2 finalUv    = vTextureCoord + distortion * 0.04 * disp.a;
  gl_FragColor    = texture2D(uTexture, finalUv);
}
JS — ブラシ生成 & テクスチャ更新ループ
// ノーマルマップ状のブラシを Canvas で手書き生成
const imgData = bCtx.createImageData(brushSize, brushSize);
for (let y = 0; y < brushSize; y++) {
  for (let x = 0; x < brushSize; x++) {
    const dx = x - radius, dy = y - radius;
    const dist = Math.sqrt(dx*dx + dy*dy);
    const i = (y * brushSize + x) * 4;
    if (dist <= radius) {
      imgData.data[i]   = (dx/radius + 1) / 2 * 255; // R → X 方向
      imgData.data[i+1] = (dy/radius + 1) / 2 * 255; // G → Y 方向
      imgData.data[i+3] = (1 - dist/radius) * 255;    // A → 減衰
    }
  }
}

// フレームごとにテクスチャ更新を通知
plane.onRender(() => {
  if (plane.textures?.length > 1) plane.textures[1].needUpdate();
});

✓ 長所

  • GLSL フルアクセス — GPU の全能力をシェーダーで制御
  • DOM 要素と WebGL が完全同期(スクロール・リサイズ追従)
  • 2D Canvas でノーマルマップを動的生成できる柔軟性
  • マウス / タッチ両対応のインタラクション
  • バンドルサイズ比較的軽量(~60 KB gzip)

✗ 短所

  • GLSL の知識が必須 — 学習コストが最も高い
  • セットアップにシェーダー記述 + テクスチャ管理が必要
  • メンテナンス停止(最終リリース v8.1.6 / 2024年)
  • WebGL Inspector 必須でデバッグが煩雑
  • 複雑なシーンでは手動リソース管理が必要
◆ 2D Rendering Engine

PixiJS

ゲームエンジン級の 2D レンダリングエンジン。WebGL2 をフル活用し、 RenderTexture に波紋ブラシを動的スタンプ → DisplacementFilter で背景画像を歪める方式。 スプライト・パーティクル・多段フィルターなどを自由に組み合わせられる。

PixiJS — RenderTexture + DisplacementFilter
// 動的なディスプレイスメントマップ用テクスチャを作成
const renderTexture = PIXI.RenderTexture.create({
  width: app.screen.width, height: app.screen.height
});
const dispFilter = new PIXI.DisplacementFilter(
  new PIXI.Sprite(renderTexture)
);
dispFilter.scale.set(40, 40); // 屈折の強さ
app.stage.filters = [dispFilter];

// ポインター移動で波紋スタンプを追加
app.stage.on('pointermove', (e) => {
  const r = new PIXI.Sprite(brushTexture);
  r.anchor.set(0.5);
  r.x = e.global.x; r.y = e.global.y;
  r.scale.set(0.2); r.alpha = 1;
  rippleContainer.addChild(r);
  ripples.push(r);
});

// 毎フレーム: 波を広げて RenderTexture に焼き付ける
app.ticker.add(() => {
  ripples.forEach((r, i) => {
    r.scale.x += 0.03; r.scale.y += 0.03;
    r.alpha   -= 0.03;
    if (r.alpha <= 0) { rippleContainer.removeChild(r); ripples.splice(i,1); }
  });
  app.renderer.render(rippleContainer, { renderTexture, clear: true });
});

✓ 長所

  • 最高レベルのレンダリングパフォーマンス(WebGL2 最適化)
  • Blur / Displacement / ColorMatrix など Filter が標準搭載
  • RenderTexture で動的テクスチャ生成が簡単
  • Pointer Events API で統一されたマウス / タッチ操作
  • 活発なエコシステム(v8.18.1 / 2026年4月も継続リリース)

✗ 短所

  • フルインポートで ~470 KB gzip(v8 tree-shaking で大幅削減可)
  • DOM 要素との統合が難しい(Canvas が独立して存在)
  • 水面特化でなく汎用エンジンなので実装量が多い
  • HTML コンテンツとの z-index 管理が必要
  • v7→v8 で破壊的変更(DisplacementFilter の API も変更 / 当デモは v7 ベース)
◆ jQuery Plugin

jQuery Ripples

最も手軽な水面波紋ライブラリ。WebGL による物理ベースの水面シミュレーション(反射・屈折)を わずか 4〜5 行で実装できる。background-image の DOM 要素に直接適用可能で、 既存サイトへの追加コストが最も低い。

jQuery Ripples — 最小実装
// これだけで物理シミュレーション付きの水面エフェクト完成
$('#canvas-bg').ripples({
  resolution:  512,   // テクスチャ解像度(高いほど重い)
  dropRadius:  20,    // 波紋の半径 (px)
  perturbance: 0.04,  // 屈折の強さ (0 〜 1)
  interactive: true   // マウス / タッチ操作を有効化
});

// 任意の位置に波紋を追加 (雨・クリック等)
$('#canvas-bg').ripples('drop', x, y, radius, strength);

✓ 長所

  • 実装が超シンプル — 数行でプロ級の波紋エフェクト
  • 物理ベースの水面シミュレーション(波の伝播が自然)
  • background-image 要素に直接適用 — DOM 変更不要
  • drop() API で雨・クリックなど外部トリガーも可能
  • 既存 jQuery サイトへの追加が最も容易

✗ 短所

  • jQuery への依存(現代的プロジェクトとの相性が悪い)
  • ライブラリ実質停止(最終リリース v0.6.3 / 2020年、以降更新なし)
  • カスタマイズ性が低い(設定パラメーターが 4 つのみ)
  • シェーダーへのアクセス不可
  • 高解像度設定でモバイルパフォーマンスが低下する
04

CSS アプローチ

◆ Zero JavaScript

JS なしでも波紋・液体・歪みエフェクトを近似的に表現できる手法。 動的なマウス追従は不可だが、静的・ホバー限定の演出や SSR 環境では有効な選択肢。

① @keyframes — 波紋リング(live)
② backdrop-filter — ガラス(live)
backdrop-filter
③ SVG feTurbulence — 歪み(live)
水面

① @keyframes — 同心円波紋リング

CSS — 擬似要素で波紋リングを生成
/* 擬似要素 2 枚をずらして同心円を作る */
.ripple::before, .ripple::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.6);
  animation: rippleOut 2s linear infinite;
}
.ripple::after { animation-delay: 1s; }

@keyframes rippleOut {
  from { transform: scale(1);   opacity: 1; }
  to   { transform: scale(2.8); opacity: 0; }
}

② backdrop-filter — ガラス / 歪みエフェクト

CSS — backdrop-filter blur + saturate
/* 背景を光学ガラス越しに見せる(グローバル対応率 92% / 2026年5月) */
.glass {
  /* Safari 18 以前は -webkit- prefix が必要 */
  -webkit-backdrop-filter: blur(12px) saturate(150%) brightness(110%);
          backdrop-filter: blur(12px) saturate(150%) brightness(110%);
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.12);
  transition: backdrop-filter 0.4s ease;
}
.glass:hover {
  -webkit-backdrop-filter: blur(24px) saturate(200%);
          backdrop-filter: blur(24px) saturate(200%);
}
/* ⚠ CSS 変数は -webkit-backdrop-filter では未サポート(Safari 制限) */

③ SVG feTurbulence — 有機的ノイズ歪み

SVG Filter + CSS — 液体的な歪みアニメーション
<svg style="display:none">
  <filter id="liquid">
    <feTurbulence type="fractalNoise"
      baseFrequency="0.015" numOctaves="3" seed="2" result="noise">
      <animate attributeName="baseFrequency"
        values="0.01;0.02;0.01" dur="4s" repeatCount="indefinite"/>
    </feTurbulence>
    <feDisplacementMap in="SourceGraphic" in2="noise"
      scale="20" xChannelSelector="R" yChannelSelector="G"/>
  </filter>
</svg>

/* CSS で適用 — JS 不要 */
.liquid-morph { filter: url(#liquid); }

✓ CSS の強み

  • ゼロ依存 — バンドルサイズへの影響なし
  • SSR / 静的サイトで完全動作(Next.js, Astro 等)
  • backdrop-filter は GPU アクセラレーション対応
  • 宣言的なため保守・変更が容易
  • アクセシビリティ対応が自然(reduced-motion 対応しやすい)

✗ CSS の限界

  • マウス追従型の動的波紋は JS なしでは不可能
  • SVG feTurbulence は大きい要素で CPU 負荷大
  • ピクセル単位の制御は WebGL に劣る
  • 複雑な物理シミュレーション(波の伝播など)は再現不可
  • ブラウザ間の filter 実装差異に注意が必要
05

ユースケース別 推奨

GPU 全力・独自エフェクト

GLSL シェーダーを完全制御したい、DOM 要素に独自 WebGL エフェクトを重ねたいケース

→ Curtains.js

インタラクティブ体験・ゲーム UI

スプライト・パーティクル・多重フィルターを組み合わせた複雑なビジュアルが必要なケース

→ PixiJS

既存サイトへ即追加・PoC

jQuery 環境に手軽に波紋を追加したい、プロトタイプや検証目的のレガシー案件

→ jQuery Ripples

軽量・静的・アクセシブル

ゼロ JS、SSR 対応、インタラクション不要の装飾的エフェクト。ローディングや背景演出

→ CSS Only

検証まとめ

jQuery Ripples は最も手軽だが、jQuery 依存 + 事実上停止(最終 v0.6.3 / 2020年)というリスクがありプロダクション採用は慎重に。 PixiJS は v8.18(2026年4月)まで活発に開発が続いており、tree-shaking 対応で軽量化も可能。ただし v7→v8 で破壊的変更があるため既存コードの移行コストに注意。 Curtains.js は GPU 制御の自由度が最高で DOM 要素との統合が容易だが、2024年を最後に開発停止しており長期採用はリスクがある。 CSS はゼロコストで近似表現が可能だが、動的インタラクションには根本的な限界がある。

プロダクション環境では PixiJS または Curtains.js の二択、 素早いプロトタイプには jQuery Ripples、 ゼロ JS 環境では CSS + SVG feTurbulence の組み合わせが推奨される。