グーフィルター(粘性融合)
feGaussianBlurとfeColorMatrixで要素同士が溶け合うメタボール表現。ローダーやメニュー展開の演出に最適です。
ライブデモ
使用例(お題: アイドルグループ Sakura)
この技法を「アイドルグループ Sakura」というテーマのダミーサイトで実際に使った例です。
HTML
<!-- Sakura:ライブ告知ヒーロー。ペンライトの光が溶け合うグーフィルター -->
<section class="sk-live">
<!-- グーフィルター定義(不可視) -->
<svg class="sk-defs" aria-hidden="true" width="0" height="0">
<defs>
<filter id="skGoo">
<feGaussianBlur in="SourceGraphic" stdDeviation="9" result="blur" />
<feColorMatrix in="blur" mode="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -9" result="goo" />
<feBlend in="SourceGraphic" in2="goo" />
</filter>
</defs>
</svg>
<!-- 主役:周回する光がメタボール状に融合 -->
<div class="sk-blobs" aria-hidden="true">
<span class="sk-blob sk-core"></span>
<span class="sk-blob sk-b0"></span>
<span class="sk-blob sk-b1"></span>
<span class="sk-blob sk-b2"></span>
<span class="sk-blob sk-b3"></span>
</div>
<div class="sk-live__copy">
<span class="sk-live__tag">SAKURA SPRING LIVE 2026</span>
<h1 class="sk-live__title">満開のステージで、<br>会いに行くよ。</h1>
<p class="sk-live__date">4.18 SAT / 4.19 SUN @さくらアリーナ</p>
<a class="sk-live__btn" href="#">チケット先行抽選に応募</a>
</div>
</section>
CSS
/* Sakura:ライブ告知ヒーロー(グーフィルターのペンライト融合) */
:root {
--pink: #ffd1e0;
--pink-deep: #ff6fa3;
}
* { box-sizing: border-box; }
body {
margin: 0;
height: 400px;
font-family: "Hiragino Kaku Gothic ProN", "Yu Gothic", system-ui, sans-serif;
overflow: hidden;
}
.sk-live {
position: relative;
height: 400px;
display: grid;
place-items: center;
text-align: center;
color: #fff;
background:
radial-gradient(110% 90% at 50% 110%, #ff9ec4 0%, #d96aa0 38%, #6e3a63 100%);
}
.sk-defs { position: absolute; }
/* 融合エリア。filterは親に1回だけ */
.sk-blobs {
position: absolute;
inset: 0;
filter: url(#skGoo);
opacity: 0.9;
}
.sk-blob {
position: absolute;
top: 50%;
left: 50%;
border-radius: 50%;
/* ペンライトの光:中心が白く外がピンク */
background-image: radial-gradient(circle at 35% 30%, #ffffff, var(--pink) 45%, var(--pink-deep) 100%);
}
.sk-core { width: 120px; height: 120px; margin: -60px 0 0 -60px; }
.sk-b0 { width: 60px; height: 60px; margin: -30px 0 0 -30px; animation: skOrbit 5s linear infinite; }
.sk-b1 { width: 48px; height: 48px; margin: -24px 0 0 -24px; animation: skOrbit 6.5s linear infinite reverse; }
.sk-b2 { width: 70px; height: 70px; margin: -35px 0 0 -35px; animation: skOrbit2 5.6s linear infinite; }
.sk-b3 { width: 40px; height: 40px; margin: -20px 0 0 -20px; animation: skOrbit2 7.4s linear infinite reverse; }
@keyframes skOrbit {
from { transform: rotate(0deg) translateX(110px) rotate(0deg); }
to { transform: rotate(360deg) translateX(110px) rotate(-360deg); }
}
@keyframes skOrbit2 {
from { transform: rotate(0deg) translateX(150px) rotate(0deg); }
to { transform: rotate(360deg) translateX(150px) rotate(-360deg); }
}
/* コピーは融合の上に重ねる */
.sk-live__copy { position: relative; z-index: 2; padding: 0 22px; }
.sk-live__tag {
display: inline-block;
font-size: 10px;
letter-spacing: 0.28em;
font-weight: 700;
padding: 5px 14px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.22);
-webkit-backdrop-filter: blur(4px);
backdrop-filter: blur(4px);
}
.sk-live__title {
margin: 16px 0 12px;
font-size: 28px;
line-height: 1.45;
font-weight: 800;
text-shadow: 0 4px 16px rgba(110, 58, 99, 0.6);
}
.sk-live__date {
margin: 0 0 20px;
font-size: 13px;
letter-spacing: 0.04em;
color: rgba(255, 255, 255, 0.92);
}
.sk-live__btn {
display: inline-block;
padding: 12px 26px;
border-radius: 999px;
background: #fff;
color: var(--pink-deep);
font-size: 13px;
font-weight: 800;
text-decoration: none;
box-shadow: 0 10px 26px rgba(255, 111, 163, 0.45);
transition: transform 0.2s;
}
.sk-live__btn:hover { transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) {
/* 静止時は少しずらして固める */
.sk-blob { animation: none !important; }
.sk-b0 { transform: translateX(90px); }
.sk-b1 { transform: translate(-80px, 40px); }
.sk-b2 { transform: translate(70px, -70px); }
.sk-b3 { transform: translate(-60px, -60px); }
.sk-live__btn { transition: none; }
}
JavaScript
// 中央コアをゆっくり脈動させ、ペンライトの「光のかたまり」感を強める
const core = document.querySelector(".sk-core");
if (core) {
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!reduce) {
let t = 0;
const pulse = () => {
t += 0.03;
// 0.92〜1.08 の範囲でゆっくり拡縮
const s = 1 + Math.sin(t) * 0.08;
core.style.transform = `translate(-50%, -50%) scale(${s.toFixed(3)})`;
requestAnimationFrame(pulse);
};
// marginで中央化済みなので、transform原点を中心へ揃えて拡縮
core.style.margin = "0";
core.style.transformOrigin = "center";
requestAnimationFrame(pulse);
}
}
コード
HTML
<!-- SVGグーフィルター: blur+colormatrixで要素が粘性をもって融合する -->
<div class="goo-stage">
<!-- フィルター定義(不可視) -->
<svg class="defs" aria-hidden="true" width="0" height="0">
<defs>
<filter id="goo">
<!-- ぼかして -->
<feGaussianBlur in="SourceGraphic" stdDeviation="9" result="blur" />
<!-- アルファのコントラストを強めて輪郭をくっつける -->
<feColorMatrix in="blur" mode="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -9" result="goo" />
<feBlend in="SourceGraphic" in2="goo" />
</filter>
</defs>
</svg>
<!-- このコンテナにフィルターをかけ、中の円が融合する -->
<div class="blobs">
<span class="blob b0"></span>
<span class="blob b1"></span>
<span class="blob b2"></span>
<span class="blob b3"></span>
<span class="blob core"></span>
</div>
<p class="caption">gooey filter — メタボール風の融合</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%, #312e81 0%, #1e1b4b 45%, #0a0a1f 100%);
overflow: hidden;
}
.goo-stage {
display: grid;
justify-items: center;
gap: 18px;
}
.defs { position: absolute; }
/* 融合エリア。filterは親に1回だけかける */
.blobs {
position: relative;
width: 260px;
height: 220px;
filter: url(#goo);
}
.blob {
position: absolute;
border-radius: 50%;
background: #f472b6;
/* グラデで艶を出す */
background-image: radial-gradient(circle at 35% 30%, #fbcfe8, #f472b6 45%, #c026d3 100%);
top: 50%;
left: 50%;
}
/* 中央のコア */
.core {
width: 90px; height: 90px;
margin: -45px 0 0 -45px;
}
/* 周回する4つの粒。サイズと半径・速度をずらす */
.b0 { width: 46px; height: 46px; margin: -23px 0 0 -23px; animation: orbit 4.5s linear infinite; }
.b1 { width: 38px; height: 38px; margin: -19px 0 0 -19px; animation: orbit 6s linear infinite reverse; }
.b2 { width: 54px; height: 54px; margin: -27px 0 0 -27px; animation: orbit2 5.2s linear infinite; }
.b3 { width: 30px; height: 30px; margin: -15px 0 0 -15px; animation: orbit2 7s linear infinite reverse; }
@keyframes orbit {
from { transform: rotate(0deg) translateX(70px) rotate(0deg); }
to { transform: rotate(360deg) translateX(70px) rotate(-360deg); }
}
@keyframes orbit2 {
from { transform: rotate(0deg) translateX(95px) rotate(0deg); }
to { transform: rotate(360deg) translateX(95px) rotate(-360deg); }
}
.caption {
margin: 0;
font-size: 12px;
letter-spacing: .14em;
text-transform: uppercase;
color: #c7d2fe;
}
@media (prefers-reduced-motion: reduce) {
.blob { animation: none !important; }
/* 静止時は少しずらして固める */
.b0 { transform: translateX(60px); }
.b1 { transform: translate(-55px, 30px); }
.b2 { transform: translate(50px, -45px); }
.b3 { transform: translate(-40px, -40px); }
}
JavaScript
// このデモはCSSアニメ+SVGフィルターのみで完結(JS不要)。
// ポインタ追従の遊びを少しだけ追加:マウス位置にコアが寄る。
const stage = document.querySelector(".blobs");
const core = document.querySelector(".core");
if (stage && core) {
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!reduce) {
stage.addEventListener("pointermove", (e) => {
const r = stage.getBoundingClientRect();
// 中心からの相対位置を小さく反映(最大±18px)
const dx = ((e.clientX - r.left) / r.width - 0.5) * 36;
const dy = ((e.clientY - r.top) / r.height - 0.5) * 36;
core.style.transform = `translate(${dx}px, ${dy}px)`;
});
stage.addEventListener("pointerleave", () => {
core.style.transform = "translate(0,0)";
});
}
}
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「グーフィルター(粘性融合)」の効果を追加してください。
# 追加してほしい効果
グーフィルター(粘性融合)(SVG エフェクト)
feGaussianBlurとfeColorMatrixで要素同士が溶け合うメタボール表現。ローダーやメニュー展開の演出に最適です。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- SVGグーフィルター: blur+colormatrixで要素が粘性をもって融合する -->
<div class="goo-stage">
<!-- フィルター定義(不可視) -->
<svg class="defs" aria-hidden="true" width="0" height="0">
<defs>
<filter id="goo">
<!-- ぼかして -->
<feGaussianBlur in="SourceGraphic" stdDeviation="9" result="blur" />
<!-- アルファのコントラストを強めて輪郭をくっつける -->
<feColorMatrix in="blur" mode="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -9" result="goo" />
<feBlend in="SourceGraphic" in2="goo" />
</filter>
</defs>
</svg>
<!-- このコンテナにフィルターをかけ、中の円が融合する -->
<div class="blobs">
<span class="blob b0"></span>
<span class="blob b1"></span>
<span class="blob b2"></span>
<span class="blob b3"></span>
<span class="blob core"></span>
</div>
<p class="caption">gooey filter — メタボール風の融合</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%, #312e81 0%, #1e1b4b 45%, #0a0a1f 100%);
overflow: hidden;
}
.goo-stage {
display: grid;
justify-items: center;
gap: 18px;
}
.defs { position: absolute; }
/* 融合エリア。filterは親に1回だけかける */
.blobs {
position: relative;
width: 260px;
height: 220px;
filter: url(#goo);
}
.blob {
position: absolute;
border-radius: 50%;
background: #f472b6;
/* グラデで艶を出す */
background-image: radial-gradient(circle at 35% 30%, #fbcfe8, #f472b6 45%, #c026d3 100%);
top: 50%;
left: 50%;
}
/* 中央のコア */
.core {
width: 90px; height: 90px;
margin: -45px 0 0 -45px;
}
/* 周回する4つの粒。サイズと半径・速度をずらす */
.b0 { width: 46px; height: 46px; margin: -23px 0 0 -23px; animation: orbit 4.5s linear infinite; }
.b1 { width: 38px; height: 38px; margin: -19px 0 0 -19px; animation: orbit 6s linear infinite reverse; }
.b2 { width: 54px; height: 54px; margin: -27px 0 0 -27px; animation: orbit2 5.2s linear infinite; }
.b3 { width: 30px; height: 30px; margin: -15px 0 0 -15px; animation: orbit2 7s linear infinite reverse; }
@keyframes orbit {
from { transform: rotate(0deg) translateX(70px) rotate(0deg); }
to { transform: rotate(360deg) translateX(70px) rotate(-360deg); }
}
@keyframes orbit2 {
from { transform: rotate(0deg) translateX(95px) rotate(0deg); }
to { transform: rotate(360deg) translateX(95px) rotate(-360deg); }
}
.caption {
margin: 0;
font-size: 12px;
letter-spacing: .14em;
text-transform: uppercase;
color: #c7d2fe;
}
@media (prefers-reduced-motion: reduce) {
.blob { animation: none !important; }
/* 静止時は少しずらして固める */
.b0 { transform: translateX(60px); }
.b1 { transform: translate(-55px, 30px); }
.b2 { transform: translate(50px, -45px); }
.b3 { transform: translate(-40px, -40px); }
}
【JavaScript】
// このデモはCSSアニメ+SVGフィルターのみで完結(JS不要)。
// ポインタ追従の遊びを少しだけ追加:マウス位置にコアが寄る。
const stage = document.querySelector(".blobs");
const core = document.querySelector(".core");
if (stage && core) {
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!reduce) {
stage.addEventListener("pointermove", (e) => {
const r = stage.getBoundingClientRect();
// 中心からの相対位置を小さく反映(最大±18px)
const dx = ((e.clientX - r.left) / r.width - 0.5) * 36;
const dy = ((e.clientY - r.top) / r.height - 0.5) * 36;
core.style.transform = `translate(${dx}px, ${dy}px)`;
});
stage.addEventListener("pointerleave", () => {
core.style.transform = "translate(0,0)";
});
}
}
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。