液体ディストーション

feTurbulenceとfeDisplacementMapでノイズ歪みを与え、有機的にうねる液体表現を作るSVGフィルター。背景演出に。

#svg#filter#js#animation

ライブデモ

使用例(お題: SaaS FlowDesk)

この技法を「SaaS FlowDesk」というテーマのダミーサイトで実際に使った例です。

HTML
<!-- FlowDesk:CTAセクション。背景の有機的な液体ブロブが主役 -->
<section class="fd-cta">
  <!-- 主役:feTurbulence+feDisplacementMapでうねる液体ブロブ -->
  <svg class="fd-liquid" viewBox="0 0 480 360" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
    <defs>
      <linearGradient id="fdLiq" x1="0" y1="0" x2="1" y2="1">
        <stop offset="0%" stop-color="#4f7cff" />
        <stop offset="55%" stop-color="#7aa0ff" />
        <stop offset="100%" stop-color="#1b3a8c" />
      </linearGradient>
      <!-- ノイズで歪ませるフィルター。baseFrequencyをJSで揺らす -->
      <filter id="fdDistort">
        <feTurbulence type="fractalNoise" baseFrequency="0.011" numOctaves="2"
                      seed="7" result="noise" />
        <feDisplacementMap in="SourceGraphic" in2="noise" scale="34"
                           xChannelSelector="R" yChannelSelector="G" />
      </filter>
    </defs>
    <g filter="url(#fdDistort)">
      <circle cx="120" cy="120" r="150" fill="url(#fdLiq)" opacity="0.9" />
      <circle cx="360" cy="250" r="130" fill="#3a63e0" opacity="0.7" />
    </g>
  </svg>

  <!-- 液体の上に重なるCTAコピー -->
  <div class="fd-cta__inner">
    <span class="fd-cta__eyebrow">START FREE</span>
    <h2 class="fd-cta__title">チームの流れを、<br>今日から整える。</h2>
    <p class="fd-cta__lead">クレジットカード不要。14日間すべての機能を無料でお試しいただけます。</p>
    <div class="fd-cta__actions">
      <a class="fd-cta__btn fd-cta__btn--primary" href="#">無料で始める</a>
      <a class="fd-cta__btn fd-cta__btn--ghost" href="#">資料をダウンロード</a>
    </div>
  </div>
</section>
CSS
/* FlowDesk:CTAセクション(液体ディストーション背景) */
:root {
  --navy: #0f1b34;
  --blue: #4f7cff;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  height: 400px;
  font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
  overflow: hidden;
}

.fd-cta {
  position: relative;
  height: 400px;
  display: grid;
  place-items: center;
  text-align: center;
  color: #fff;
  background: var(--navy);
  overflow: hidden;
}

/* 主役:背景いっぱいに広がるうねる液体 */
.fd-liquid {
  position: absolute;
  inset: -10%;
  width: 120%;
  height: 120%;
  filter: drop-shadow(0 16px 50px rgba(79, 124, 255, 0.35));
}

/* 液体の上に重なるコピー */
.fd-cta__inner { position: relative; z-index: 2; padding: 0 24px; max-width: 460px; }
.fd-cta__eyebrow {
  font-size: 11px;
  letter-spacing: 0.28em;
  font-weight: 700;
  color: #bcd0ff;
}
.fd-cta__title {
  margin: 12px 0 12px;
  font-size: 28px;
  line-height: 1.4;
  font-weight: 800;
  text-shadow: 0 6px 22px rgba(7, 14, 30, 0.5);
}
.fd-cta__lead {
  margin: 0 auto 22px;
  max-width: 360px;
  font-size: 13px;
  line-height: 1.8;
  color: rgba(255, 255, 255, 0.9);
}
.fd-cta__actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.fd-cta__btn {
  display: inline-block;
  padding: 11px 22px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 700;
  text-decoration: none;
  transition: transform 0.2s, background 0.2s;
}
.fd-cta__btn--primary {
  background: #fff;
  color: var(--blue);
  box-shadow: 0 10px 26px rgba(7, 14, 30, 0.45);
}
.fd-cta__btn--primary:hover { transform: translateY(-2px); }
.fd-cta__btn--ghost {
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.4);
}
.fd-cta__btn--ghost:hover { background: rgba(255, 255, 255, 0.22); }

@media (prefers-reduced-motion: reduce) {
  .fd-cta__btn { transition: none; }
}
JavaScript
// feTurbulenceのbaseFrequencyを時間で揺らし、CTA背景の液体をうねらせる
const turb = document.querySelector("#fdDistort feTurbulence");

if (turb) {
  const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

  if (reduce) {
    // 動きを止めて落ち着いた歪みで固定
    turb.setAttribute("baseFrequency", "0.011");
  } else {
    let t = 0;
    const animate = () => {
      t += 0.01;
      // 0.007〜0.016あたりを正弦波でゆっくり往復
      const fx = 0.011 + Math.sin(t) * 0.005;
      const fy = 0.011 + Math.cos(t * 0.8) * 0.004;
      turb.setAttribute("baseFrequency", `${fx.toFixed(4)} ${fy.toFixed(4)}`);
      requestAnimationFrame(animate);
    };
    requestAnimationFrame(animate);
  }
}

コード

HTML
<!-- 液体ディストーション: feTurbulence+feDisplacementMapでゆらぐ有機的な形 -->
<div class="liquid-stage">
  <svg viewBox="0 0 240 240" class="liquid" role="img" aria-label="ゆらめく液体状の円">
    <defs>
      <linearGradient id="liq" x1="0" y1="0" x2="1" y2="1">
        <stop offset="0%" stop-color="#34d399" />
        <stop offset="55%" stop-color="#22d3ee" />
        <stop offset="100%" stop-color="#6366f1" />
      </linearGradient>
      <!-- ノイズで歪ませるフィルター。baseFrequencyをJSで揺らす -->
      <filter id="distort">
        <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2"
                      seed="4" result="noise" />
        <feDisplacementMap in="SourceGraphic" in2="noise" scale="26"
                           xChannelSelector="R" yChannelSelector="G" />
      </filter>
    </defs>
    <!-- このグループにフィルターを適用 -->
    <g filter="url(#distort)">
      <circle cx="120" cy="120" r="78" fill="url(#liq)" />
      <circle cx="120" cy="120" r="78" fill="none" stroke="#e0fbff" stroke-width="2" opacity="0.5" />
    </g>
  </svg>
  <p class="caption">feTurbulence + feDisplacementMap</p>
</div>
CSS
* { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  font-family: "Segoe UI", system-ui, sans-serif;
  background: radial-gradient(120% 120% at 50% 10%, #0c1424 0%, #060b16 60%, #03060d 100%);
  overflow: hidden;
}
.liquid-stage {
  display: grid;
  justify-items: center;
  gap: 18px;
}
.liquid {
  width: min(60vw, 240px);
  height: auto;
  filter: drop-shadow(0 16px 50px rgba(34, 211, 238, .35));
  /* ゆっくり回して質感を見せる */
  animation: rotate 22s linear infinite;
}
@keyframes rotate { to { transform: rotate(360deg); } }

.caption {
  margin: 0;
  font-size: 12px;
  letter-spacing: .12em;
  color: #93c5fd;
  font-family: ui-monospace, "Consolas", monospace;
}

@media (prefers-reduced-motion: reduce) {
  .liquid { animation: none; }
}
JavaScript
// feTurbulenceのbaseFrequencyを時間で揺らし、液体がうねる表現を作る
const turb = document.querySelector("#distort feTurbulence");

if (turb) {
  const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

  if (reduce) {
    // 動きを止めて落ち着いた歪みで固定
    turb.setAttribute("baseFrequency", "0.012");
  } else {
    let t = 0;
    const animate = () => {
      t += 0.012;
      // 0.008〜0.018あたりを正弦波でゆっくり往復
      const fx = 0.012 + Math.sin(t) * 0.006;
      const fy = 0.012 + Math.cos(t * 0.8) * 0.005;
      turb.setAttribute("baseFrequency", `${fx.toFixed(4)} ${fy.toFixed(4)}`);
      requestAnimationFrame(animate);
    };
    requestAnimationFrame(animate);
  }
}

🤖 AIエージェント用プロンプト

このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「液体ディストーション」の効果を追加してください。

# 追加してほしい効果
液体ディストーション(SVG エフェクト)
feTurbulenceとfeDisplacementMapでノイズ歪みを与え、有機的にうねる液体表現を作るSVGフィルター。背景演出に。

# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- 液体ディストーション: feTurbulence+feDisplacementMapでゆらぐ有機的な形 -->
<div class="liquid-stage">
  <svg viewBox="0 0 240 240" class="liquid" role="img" aria-label="ゆらめく液体状の円">
    <defs>
      <linearGradient id="liq" x1="0" y1="0" x2="1" y2="1">
        <stop offset="0%" stop-color="#34d399" />
        <stop offset="55%" stop-color="#22d3ee" />
        <stop offset="100%" stop-color="#6366f1" />
      </linearGradient>
      <!-- ノイズで歪ませるフィルター。baseFrequencyをJSで揺らす -->
      <filter id="distort">
        <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2"
                      seed="4" result="noise" />
        <feDisplacementMap in="SourceGraphic" in2="noise" scale="26"
                           xChannelSelector="R" yChannelSelector="G" />
      </filter>
    </defs>
    <!-- このグループにフィルターを適用 -->
    <g filter="url(#distort)">
      <circle cx="120" cy="120" r="78" fill="url(#liq)" />
      <circle cx="120" cy="120" r="78" fill="none" stroke="#e0fbff" stroke-width="2" opacity="0.5" />
    </g>
  </svg>
  <p class="caption">feTurbulence + feDisplacementMap</p>
</div>

【CSS】
* { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  font-family: "Segoe UI", system-ui, sans-serif;
  background: radial-gradient(120% 120% at 50% 10%, #0c1424 0%, #060b16 60%, #03060d 100%);
  overflow: hidden;
}
.liquid-stage {
  display: grid;
  justify-items: center;
  gap: 18px;
}
.liquid {
  width: min(60vw, 240px);
  height: auto;
  filter: drop-shadow(0 16px 50px rgba(34, 211, 238, .35));
  /* ゆっくり回して質感を見せる */
  animation: rotate 22s linear infinite;
}
@keyframes rotate { to { transform: rotate(360deg); } }

.caption {
  margin: 0;
  font-size: 12px;
  letter-spacing: .12em;
  color: #93c5fd;
  font-family: ui-monospace, "Consolas", monospace;
}

@media (prefers-reduced-motion: reduce) {
  .liquid { animation: none; }
}

【JavaScript】
// feTurbulenceのbaseFrequencyを時間で揺らし、液体がうねる表現を作る
const turb = document.querySelector("#distort feTurbulence");

if (turb) {
  const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

  if (reduce) {
    // 動きを止めて落ち着いた歪みで固定
    turb.setAttribute("baseFrequency", "0.012");
  } else {
    let t = 0;
    const animate = () => {
      t += 0.012;
      // 0.008〜0.018あたりを正弦波でゆっくり往復
      const fx = 0.012 + Math.sin(t) * 0.006;
      const fy = 0.012 + Math.cos(t * 0.8) * 0.005;
      turb.setAttribute("baseFrequency", `${fx.toFixed(4)} ${fy.toFixed(4)}`);
      requestAnimationFrame(animate);
    };
    requestAnimationFrame(animate);
  }
}

# 外部ライブラリ
なし(追加ライブラリ不要)

# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。