Gradual Blur
A liquid blur effect using layered backdrop filters with gradient masks. Perfect for hero sections, image overlays, and content fades.
Preview
Loading preview…
Customize
Strength1.5
Layers7
Position
Height40
"use client";
import { useMemo } from "react";
import styles from "./GradualBlur.module.css";
type GradualBlurProps = {
position?: "top" | "bottom" | "block";
strength?: number;
height?: string;
divCount?: number;
zIndex?: number;
inline?: boolean;
className?: string;
};
const DIRECTION = { top: "to top", bottom: "to bottom" } as const;
export default function GradualBlur({
position = "top",
strength = 2,
height = "6rem",
divCount = 5,
zIndex = 100,
inline = false,
className,
}: GradualBlurProps) {
const blurDivs = useMemo(() => {
const increment = 100 / divCount;
const direction = DIRECTION[position];
const divs: React.ReactNode[] = [];
for (let i = 1; i <= divCount; i++) {
const blur = 0.0625 * i * strength;
const p1 = Math.round((increment * i - increment) * 10) / 10;
const p2 = Math.round(increment * i * 10) / 10;
const p3 = Math.round((increment * i + increment) * 10) / 10;
const p4 = Math.round((increment * i + increment * 2) * 10) / 10;
let gradient = `transparent ${p1}%, black ${p2}%`;
if (p3 <= 100) gradient += `, black ${p3}%`;
if (p4 <= 100) gradient += `, transparent ${p4}%`;
const mask = `linear-gradient(${direction}, ${gradient})`;
divs.push(
<div
key={i}
className={styles.layer}
style={{
maskImage: mask,
WebkitMaskImage: mask,
backdropFilter: `blur(${blur.toFixed(3)}rem)`,
WebkitBackdropFilter: `blur(${blur.toFixed(3)}rem)`,
}}
/>
);
}
return divs;
}, [position, strength, divCount]);
const cls = [
styles.container,
inline ? styles.inline : styles.fixed,
className,
]
.filter(Boolean)
.join(" ");
return (
<div
className={cls}
style={{ [position]: 0, height, zIndex }}
>
{blurDivs}
</div>
);
}