液体ディストーション
feTurbulenceとfeDisplacementMapでノイズ歪みを与え、有機的にうねる液体表現を作るSVGフィルター。背景演出に。
ライブデモ
使用例(お題: 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で提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。