Fondo de metabolas líquidas
Círculos de color que se funden como líquido gracias a un filtro SVG gooey; solo CSS y SVG.
Todo se mezcla
Código completo
Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.
"use client";
import { useId, useState, type CSSProperties, type ReactNode } from "react";
/** Fondo de metabolas: círculos de color que se funden como líquido gracias a un filtro SVG "gooey". Solo CSS y SVG, con botón de pausa. React + TypeScript, sin dependencias. */
export type FondoMetabolasProps = {
colors?: string[];
children?: ReactNode;
className?: string;
style?: CSSProperties;
};
const CSS = `
.gcfmb-root { box-sizing: border-box; position: relative; isolation: isolate; container-type: inline-size; width: 100%; min-height: 480px; overflow: hidden; display: grid; place-items: center; background: #fff3e6; color: #2b1a3a; font: 500 16px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; }
.gcfmb-root *, .gcfmb-root *::before, .gcfmb-root *::after { box-sizing: border-box; }
.gcfmb-root :focus-visible { outline: 2px solid #2b1a3a; outline-offset: 3px; }
.gcfmb-root[data-paused="true"] .gcfmb-b { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) { .gcfmb-b { animation: none !important; } }
.gcfmb-field { position: absolute; inset: 0; z-index: -1; filter: var(--gcfmb-filter); }
.gcfmb-b { position: absolute; width: var(--z); height: var(--z); border-radius: 50%; background: var(--c); left: var(--x); top: var(--y); will-change: transform; animation: gcfmb-move var(--t) ease-in-out var(--d) infinite alternate; }
.gcfmb-svg { position: absolute; width: 0; height: 0; }
.gcfmb-pause { position: absolute; right: 14px; bottom: 14px; z-index: 3; display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 12px; border: 0; border-radius: 999px; background: #2b1a3a; color: #fff3e6; font: 600 12px/1 ui-sans-serif, system-ui, sans-serif; cursor: pointer; }
@keyframes gcfmb-move { 0% { transform: translate(0, 0); } 50% { transform: translate(var(--dx), var(--dy)); } 100% { transform: translate(calc(var(--dx) * -.6), calc(var(--dy) * .8)); } }`;
const SPEC = [
{ x: "8%", y: "12%", z: "30%", dx: "40cqi", dy: "20%", t: "11s" },
{ x: "62%", y: "6%", z: "26%", dx: "-30cqi", dy: "40%", t: "13s" },
{ x: "30%", y: "55%", z: "34%", dx: "30cqi", dy: "-30%", t: "15s" },
{ x: "75%", y: "58%", z: "24%", dx: "-40cqi", dy: "-20%", t: "10s" },
{ x: "46%", y: "28%", z: "18%", dx: "20cqi", dy: "30%", t: "9s" },
];
export function FondoMetabolas({ colors = ["#ff6f61", "#ffb347", "#8a6dff", "#2ec4b6", "#ff4f9a"], children, className = "", style }: FondoMetabolasProps) {
const uid = useId().replace(/[^a-zA-Z0-9]/g, "");
const fid = `gcfmb-f-${uid}`;
const [paused, setPaused] = useState(false);
return (
<section className={`gcfmb-root ${className}`} style={{ "--gcfmb-filter": `url(#${fid})`, ...style } as CSSProperties} data-paused={paused}>
<style>{CSS}</style>
<svg className="gcfmb-svg" aria-hidden="true" focusable="false">
<filter id={fid}>
<feGaussianBlur in="SourceGraphic" stdDeviation="22" result="b" />
<feColorMatrix in="b" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 24 -10" />
</filter>
</svg>
<div className="gcfmb-field" aria-hidden="true">
{SPEC.slice(0, Math.max(3, colors.length)).map((s, i) => (
<span key={i} className="gcfmb-b" style={{ "--c": colors[i % colors.length], "--x": s.x, "--y": s.y, "--z": `min(${s.z}, 260px)`, "--dx": s.dx, "--dy": s.dy, "--t": s.t, "--d": `${-i * 2}s` } as CSSProperties} />
))}
</div>
{children}
<button className="gcfmb-pause" type="button" aria-pressed={paused} onClick={() => setPaused((value) => !value)}>
<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">{paused ? <path d="M7 4v16l13-8z" /> : <path d="M6 4h4v16H6zM14 4h4v16h-4z" />}</svg>
{paused ? "Reanudar" : "Pausar"} fondo
</button>
</section>
);
}
Úsalo en tu proyecto
Instálalo con la CLI de shadcn.
npx shadcn@latest add https://www.gassierconsulting.com/r/fondo-metabolasEjemplo de uso de Fondo de metabolas líquidas
Después de copiar fondo-metabolas.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.
import { FondoMetabolas } from "./fondo-metabolas";
export default function Ejemplo() {
return <FondoMetabolas>Contenido</FondoMetabolas>;
}Propiedades de FondoMetabolas
FondoMetabolas acepta 4 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.
| Propiedad | Tipo | Descripción |
|---|---|---|
colors? | string[] | Opcional. |
children? | ReactNode | Opcional. |
className? | string | Opcional. |
style? | CSSProperties | Opcional. |
Accesibilidad y rendimiento
El archivo tiene 59 líneas (4 KB) y define 1 animación con @keyframes. Esto es lo que hace Fondo de metabolas líquidas por quien lo usa:
- Detecta prefers-reduced-motion y baja o quita el movimiento cuando la persona lo pide.
- Muestra un anillo de foco visible al navegar con teclado (:focus-visible).
- Expone su estado a tecnologías de apoyo con atributos aria-*.
- Es un componente de cliente de Next.js: incluye la directiva "use client".