WebGL & CSS — エフェクト検証レポート
WebGL × CSS
ライブラリ比較
水面波紋エフェクトを題材に、JS/WebGL系ライブラリ 3種と CSS 系アプローチを セットアップ・パフォーマンス・カスタマイズ性など多角的に比較します。
ライブ デモ
実装済みの3つのデモを実際に操作できます。マウス / タッチで波紋を起こしてください。
ライブラリ概要
各アプローチの技術カテゴリとキースコアを一覧します。
多角的比較マトリックス
| 比較軸 | 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 必須) | 中〜高 | 低 | 低〜中 |
JS ライブラリ 詳細
Curtains.js
DOM 要素(img / video)を WebGL のプレーンにマッピングし、カスタム GLSL シェーダーで加工できるライブラリ。 波紋マップを 2D Canvas で動的生成し、フラグメントシェーダーで UV 座標を歪めることで水面効果を実装。 DOM レイアウトとの同期が完全なため、スクロール・リサイズへの追従も容易。
// 波紋を 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);
}
// ノーマルマップ状のブラシを 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 必須でデバッグが煩雑
- 複雑なシーンでは手動リソース管理が必要
PixiJS
ゲームエンジン級の 2D レンダリングエンジン。WebGL2 をフル活用し、 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 Ripples
最も手軽な水面波紋ライブラリ。WebGL による物理ベースの水面シミュレーション(反射・屈折)を わずか 4〜5 行で実装できる。background-image の DOM 要素に直接適用可能で、 既存サイトへの追加コストが最も低い。
// これだけで物理シミュレーション付きの水面エフェクト完成
$('#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 つのみ)
- シェーダーへのアクセス不可
- 高解像度設定でモバイルパフォーマンスが低下する
CSS アプローチ
JS なしでも波紋・液体・歪みエフェクトを近似的に表現できる手法。 動的なマウス追従は不可だが、静的・ホバー限定の演出や SSR 環境では有効な選択肢。
① @keyframes — 同心円波紋リング
/* 擬似要素 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 — ガラス / 歪みエフェクト
/* 背景を光学ガラス越しに見せる(グローバル対応率 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 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 実装差異に注意が必要
ユースケース別 推奨
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 の組み合わせが推奨される。