UI-компоненти Легка
Animated Grid Pattern
An SVG grid pattern with randomly highlighted cells that pulse and glow, perfect for dark hero sections and backgrounds.
Відкрити в Lab
MCP
css javascript vue svelte
Цілі: TS JS HTML React Vue Svelte
Код
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--glow-color: rgba(99, 102, 241, 0.6);
--glow-color-bright: rgba(129, 140, 248, 0.9);
--grid-line-color: rgba(255, 255, 255, 0.06);
--cell-size: 40px;
--glow-duration: 2.5s;
}
body {
font-family: system-ui, -apple-system, sans-serif;
min-height: 100vh;
background: #000;
overflow: hidden;
}
.grid-wrapper {
position: relative;
width: 100%;
height: 100vh;
display: grid;
place-items: center;
background: #0a0a0a;
overflow: hidden;
}
.grid-svg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.grid-svg rect.cell {
fill: transparent;
stroke: var(--grid-line-color);
stroke-width: 0.5;
transition: fill 0.3s ease;
}
.grid-svg rect.cell.glow {
animation: cellGlow var(--glow-duration) ease-in-out forwards;
}
@keyframes cellGlow {
0% {
fill: transparent;
filter: drop-shadow(0 0 0 transparent);
}
20% {
fill: var(--glow-color);
filter: drop-shadow(0 0 8px var(--glow-color-bright));
}
50% {
fill: var(--glow-color-bright);
filter: drop-shadow(0 0 16px var(--glow-color-bright));
}
100% {
fill: transparent;
filter: drop-shadow(0 0 0 transparent);
}
}
.grid-fade {
position: absolute;
inset: 0;
background: radial-gradient(ellipse 50% 50% at 50% 50%, transparent 30%, #0a0a0a 80%);
pointer-events: none;
}
.grid-content {
position: relative;
z-index: 10;
text-align: center;
color: #f1f5f9;
pointer-events: none;
}
.grid-title {
font-size: clamp(2rem, 5vw, 3.5rem);
font-weight: 800;
letter-spacing: -0.03em;
background: linear-gradient(135deg, #e0e7ff 0%, #818cf8 50%, #6366f1 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 0.5rem;
}
.grid-subtitle {
font-size: clamp(0.875rem, 2vw, 1.125rem);
color: rgba(148, 163, 184, 0.8);
font-weight: 400;
}// Animated Grid Pattern — randomly highlights grid cells with a glow effect
(function () {
"use strict";
const svg = document.getElementById("grid-svg");
if (!svg) return;
const CELL_SIZE = 40;
const GAP = 1;
const HIGHLIGHT_INTERVAL = 120;
const GLOW_DURATION = 2500;
const MAX_SIMULTANEOUS = 8;
let cols, rows;
const cells = [];
let activeCount = 0;
function buildGrid() {
const w = window.innerWidth;
const h = window.innerHeight;
cols = Math.ceil(w / (CELL_SIZE + GAP)) + 1;
rows = Math.ceil(h / (CELL_SIZE + GAP)) + 1;
svg.setAttribute("viewBox", `0 0 ${w} ${h}`);
svg.innerHTML = "";
cells.length = 0;
const ns = "http://www.w3.org/2000/svg";
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const rect = document.createElementNS(ns, "rect");
rect.setAttribute("x", c * (CELL_SIZE + GAP));
rect.setAttribute("y", r * (CELL_SIZE + GAP));
rect.setAttribute("width", CELL_SIZE);
rect.setAttribute("height", CELL_SIZE);
rect.setAttribute("rx", 2);
rect.classList.add("cell");
svg.appendChild(rect);
cells.push(rect);
}
}
}
function highlightRandom() {
if (cells.length === 0 || activeCount >= MAX_SIMULTANEOUS) return;
const idx = Math.floor(Math.random() * cells.length);
const cell = cells[idx];
if (cell.classList.contains("glow")) return;
cell.classList.add("glow");
activeCount++;
setTimeout(() => {
cell.classList.remove("glow");
activeCount--;
}, GLOW_DURATION);
}
buildGrid();
setInterval(highlightRandom, HIGHLIGHT_INTERVAL);
let resizeTimer;
window.addEventListener("resize", () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
activeCount = 0;
buildGrid();
}, 200);
});
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Animated Grid Pattern</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="grid-wrapper">
<svg id="grid-svg" class="grid-svg" aria-hidden="true"></svg>
<div class="grid-fade"></div>
<div class="grid-content">
<h1 class="grid-title">Animated Grid</h1>
<p class="grid-subtitle">Randomly glowing cells create a living background</p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>import { useEffect, useRef, useCallback, useState } from "react";
interface AnimatedGridPatternProps {
cellSize?: number;
gap?: number;
glowColor?: string;
glowColorBright?: string;
highlightInterval?: number;
glowDuration?: number;
maxSimultaneous?: number;
className?: string;
}
export function AnimatedGridPattern({
cellSize = 40,
gap = 1,
glowColor = "rgba(99, 102, 241, 0.6)",
glowColorBright = "rgba(129, 140, 248, 0.9)",
highlightInterval = 120,
glowDuration = 2500,
maxSimultaneous = 8,
className = "",
}: AnimatedGridPatternProps) {
const svgRef = useRef<SVGSVGElement>(null);
const cellsRef = useRef<SVGRectElement[]>([]);
const activeCountRef = useRef(0);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
const buildGrid = useCallback(() => {
const svg = svgRef.current;
if (!svg) return;
const parent = svg.parentElement;
if (!parent) return;
const w = parent.clientWidth;
const h = parent.clientHeight;
setDimensions({ width: w, height: h });
const cols = Math.ceil(w / (cellSize + gap)) + 1;
const rows = Math.ceil(h / (cellSize + gap)) + 1;
while (svg.firstChild) svg.removeChild(svg.firstChild);
cellsRef.current = [];
activeCountRef.current = 0;
const ns = "http://www.w3.org/2000/svg";
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const rect = document.createElementNS(ns, "rect");
rect.setAttribute("x", String(c * (cellSize + gap)));
rect.setAttribute("y", String(r * (cellSize + gap)));
rect.setAttribute("width", String(cellSize));
rect.setAttribute("height", String(cellSize));
rect.setAttribute("rx", "2");
rect.setAttribute("fill", "transparent");
rect.setAttribute("stroke", "rgba(255,255,255,0.06)");
rect.setAttribute("stroke-width", "0.5");
svg.appendChild(rect);
cellsRef.current.push(rect);
}
}
}, [cellSize, gap]);
useEffect(() => {
buildGrid();
let resizeTimer: ReturnType<typeof setTimeout>;
const handleResize = () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(buildGrid, 200);
};
window.addEventListener("resize", handleResize);
return () => {
clearTimeout(resizeTimer);
window.removeEventListener("resize", handleResize);
};
}, [buildGrid]);
useEffect(() => {
const interval = setInterval(() => {
const cells = cellsRef.current;
if (cells.length === 0 || activeCountRef.current >= maxSimultaneous) return;
const idx = Math.floor(Math.random() * cells.length);
const cell = cells[idx];
if (cell.dataset.active === "true") return;
cell.dataset.active = "true";
cell.setAttribute("fill", glowColor);
cell.style.filter = `drop-shadow(0 0 8px ${glowColorBright})`;
cell.style.transition = "fill 0.3s ease, filter 0.3s ease";
activeCountRef.current++;
setTimeout(() => {
cell.setAttribute("fill", glowColorBright);
cell.style.filter = `drop-shadow(0 0 16px ${glowColorBright})`;
}, glowDuration * 0.2);
setTimeout(() => {
cell.setAttribute("fill", "transparent");
cell.style.filter = "none";
cell.dataset.active = "false";
activeCountRef.current--;
}, glowDuration);
}, highlightInterval);
return () => clearInterval(interval);
}, [glowColor, glowColorBright, highlightInterval, glowDuration, maxSimultaneous]);
return (
<div
className={className}
style={{ position: "relative", width: "100%", height: "100%", overflow: "hidden" }}
>
<svg
ref={svgRef}
viewBox={`0 0 ${dimensions.width} ${dimensions.height}`}
style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }}
aria-hidden="true"
/>
<div
style={{
position: "absolute",
inset: 0,
background: "radial-gradient(ellipse 50% 50% at 50% 50%, transparent 30%, #0a0a0a 80%)",
pointerEvents: "none",
}}
/>
</div>
);
}
// Demo usage
export default function AnimatedGridPatternDemo() {
return (
<div
style={{
width: "100vw",
height: "100vh",
background: "#0a0a0a",
display: "grid",
placeItems: "center",
position: "relative",
}}
>
<AnimatedGridPattern
className=""
cellSize={40}
glowColor="rgba(99, 102, 241, 0.6)"
glowColorBright="rgba(129, 140, 248, 0.9)"
/>
<div
style={{
position: "relative",
zIndex: 10,
textAlign: "center",
pointerEvents: "none",
}}
>
<h1
style={{
fontSize: "clamp(2rem, 5vw, 3.5rem)",
fontWeight: 800,
letterSpacing: "-0.03em",
background: "linear-gradient(135deg, #e0e7ff 0%, #818cf8 50%, #6366f1 100%)",
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
backgroundClip: "text",
marginBottom: "0.5rem",
fontFamily: "system-ui, -apple-system, sans-serif",
}}
>
Animated Grid
</h1>
<p
style={{
fontSize: "clamp(0.875rem, 2vw, 1.125rem)",
color: "rgba(148, 163, 184, 0.8)",
fontFamily: "system-ui, -apple-system, sans-serif",
}}
>
Randomly glowing cells create a living background
</p>
</div>
</div>
);
}<script setup>
import { ref, onMounted, onUnmounted } from "vue";
const props = defineProps({
cellSize: { type: Number, default: 40 },
gap: { type: Number, default: 1 },
glowColor: { type: String, default: "rgba(99, 102, 241, 0.6)" },
glowColorBright: { type: String, default: "rgba(129, 140, 248, 0.9)" },
highlightInterval: { type: Number, default: 120 },
glowDuration: { type: Number, default: 2500 },
maxSimultaneous: { type: Number, default: 8 },
});
const svgEl = ref(null);
const width = ref(0);
const height = ref(0);
let cells = [];
let activeCount = 0;
let intervalId;
let resizeTimer;
function buildGrid() {
const svg = svgEl.value;
if (!svg) return;
const parent = svg.parentElement;
if (!parent) return;
width.value = parent.clientWidth;
height.value = parent.clientHeight;
const cols = Math.ceil(width.value / (props.cellSize + props.gap)) + 1;
const rows = Math.ceil(height.value / (props.cellSize + props.gap)) + 1;
while (svg.firstChild) svg.removeChild(svg.firstChild);
cells = [];
activeCount = 0;
const ns = "http://www.w3.org/2000/svg";
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const rect = document.createElementNS(ns, "rect");
rect.setAttribute("x", String(c * (props.cellSize + props.gap)));
rect.setAttribute("y", String(r * (props.cellSize + props.gap)));
rect.setAttribute("width", String(props.cellSize));
rect.setAttribute("height", String(props.cellSize));
rect.setAttribute("rx", "2");
rect.setAttribute("fill", "transparent");
rect.setAttribute("stroke", "rgba(255,255,255,0.06)");
rect.setAttribute("stroke-width", "0.5");
svg.appendChild(rect);
cells.push(rect);
}
}
}
function startHighlighting() {
intervalId = setInterval(() => {
if (cells.length === 0 || activeCount >= props.maxSimultaneous) return;
const idx = Math.floor(Math.random() * cells.length);
const cell = cells[idx];
if (cell.dataset.active === "true") return;
cell.dataset.active = "true";
cell.setAttribute("fill", props.glowColor);
cell.style.filter = `drop-shadow(0 0 8px ${props.glowColorBright})`;
cell.style.transition = "fill 0.3s ease, filter 0.3s ease";
activeCount++;
setTimeout(() => {
cell.setAttribute("fill", props.glowColorBright);
cell.style.filter = `drop-shadow(0 0 16px ${props.glowColorBright})`;
}, props.glowDuration * 0.2);
setTimeout(() => {
cell.setAttribute("fill", "transparent");
cell.style.filter = "none";
cell.dataset.active = "false";
activeCount--;
}, props.glowDuration);
}, props.highlightInterval);
}
function handleResize() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(buildGrid, 200);
}
onMounted(() => {
buildGrid();
startHighlighting();
window.addEventListener("resize", handleResize);
});
onUnmounted(() => {
clearInterval(intervalId);
clearTimeout(resizeTimer);
window.removeEventListener("resize", handleResize);
});
</script>
<template>
<div
style="width: 100vw; height: 100vh; background: #0a0a0a; display: grid; place-items: center; position: relative;"
>
<div style="position: relative; width: 100%; height: 100%; overflow: hidden;">
<svg
ref="svgEl"
:viewBox="`0 0 ${width} ${height}`"
style="position: absolute; inset: 0; width: 100%; height: 100%;"
aria-hidden="true"
></svg>
<div
style="position: absolute; inset: 0; background: radial-gradient(ellipse 50% 50% at 50% 50%, transparent 30%, #0a0a0a 80%); pointer-events: none;"
></div>
</div>
<div
style="position: absolute; z-index: 10; text-align: center; pointer-events: none;"
>
<h1
style="font-size: clamp(2rem, 5vw, 3.5rem); font-weight: 800; letter-spacing: -0.03em; background: linear-gradient(135deg, #e0e7ff 0%, #818cf8 50%, #6366f1 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin-bottom: 0.5rem; font-family: system-ui, -apple-system, sans-serif;"
>
Animated Grid
</h1>
<p
style="font-size: clamp(0.875rem, 2vw, 1.125rem); color: rgba(148, 163, 184, 0.8); font-family: system-ui, -apple-system, sans-serif;"
>
Randomly glowing cells create a living background
</p>
</div>
</div>
</template><script>
import { onMount, onDestroy } from "svelte";
export let cellSize = 40;
export let gap = 1;
export let glowColor = "rgba(99, 102, 241, 0.6)";
export let glowColorBright = "rgba(129, 140, 248, 0.9)";
export let highlightInterval = 120;
export let glowDuration = 2500;
export let maxSimultaneous = 8;
let svgEl;
let cells = [];
let activeCount = 0;
let width = 0;
let height = 0;
let intervalId;
let resizeTimer;
function buildGrid() {
if (!svgEl) return;
const parent = svgEl.parentElement;
if (!parent) return;
width = parent.clientWidth;
height = parent.clientHeight;
const cols = Math.ceil(width / (cellSize + gap)) + 1;
const rows = Math.ceil(height / (cellSize + gap)) + 1;
while (svgEl.firstChild) svgEl.removeChild(svgEl.firstChild);
cells = [];
activeCount = 0;
const ns = "http://www.w3.org/2000/svg";
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const rect = document.createElementNS(ns, "rect");
rect.setAttribute("x", String(c * (cellSize + gap)));
rect.setAttribute("y", String(r * (cellSize + gap)));
rect.setAttribute("width", String(cellSize));
rect.setAttribute("height", String(cellSize));
rect.setAttribute("rx", "2");
rect.setAttribute("fill", "transparent");
rect.setAttribute("stroke", "rgba(255,255,255,0.06)");
rect.setAttribute("stroke-width", "0.5");
svgEl.appendChild(rect);
cells.push(rect);
}
}
}
function startHighlighting() {
intervalId = setInterval(() => {
if (cells.length === 0 || activeCount >= maxSimultaneous) return;
const idx = Math.floor(Math.random() * cells.length);
const cell = cells[idx];
if (cell.dataset.active === "true") return;
cell.dataset.active = "true";
cell.setAttribute("fill", glowColor);
cell.style.filter = `drop-shadow(0 0 8px ${glowColorBright})`;
cell.style.transition = "fill 0.3s ease, filter 0.3s ease";
activeCount++;
setTimeout(() => {
cell.setAttribute("fill", glowColorBright);
cell.style.filter = `drop-shadow(0 0 16px ${glowColorBright})`;
}, glowDuration * 0.2);
setTimeout(() => {
cell.setAttribute("fill", "transparent");
cell.style.filter = "none";
cell.dataset.active = "false";
activeCount--;
}, glowDuration);
}, highlightInterval);
}
function handleResize() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(buildGrid, 200);
}
onMount(() => {
buildGrid();
startHighlighting();
window.addEventListener("resize", handleResize);
});
onDestroy(() => {
clearInterval(intervalId);
clearTimeout(resizeTimer);
window.removeEventListener("resize", handleResize);
});
</script>
<div
style="width: 100vw; height: 100vh; background: #0a0a0a; display: grid; place-items: center; position: relative;"
>
<div style="position: relative; width: 100%; height: 100%; overflow: hidden;">
<svg
bind:this={svgEl}
viewBox="0 0 {width} {height}"
style="position: absolute; inset: 0; width: 100%; height: 100%;"
aria-hidden="true"
></svg>
<div
style="position: absolute; inset: 0; background: radial-gradient(ellipse 50% 50% at 50% 50%, transparent 30%, #0a0a0a 80%); pointer-events: none;"
></div>
</div>
<div
style="position: absolute; z-index: 10; text-align: center; pointer-events: none;"
>
<h1
style="font-size: clamp(2rem, 5vw, 3.5rem); font-weight: 800; letter-spacing: -0.03em; background: linear-gradient(135deg, #e0e7ff 0%, #818cf8 50%, #6366f1 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin-bottom: 0.5rem; font-family: system-ui, -apple-system, sans-serif;"
>
Animated Grid
</h1>
<p
style="font-size: clamp(0.875rem, 2vw, 1.125rem); color: rgba(148, 163, 184, 0.8); font-family: system-ui, -apple-system, sans-serif;"
>
Randomly glowing cells create a living background
</p>
</div>
</div>Animated Grid Pattern
A mesmerizing SVG grid pattern where cells randomly highlight with a soft glow animation. Ideal as a subtle animated background for hero sections, dashboards, or landing pages.
How it works
- An SVG grid of rectangles is generated programmatically
- JavaScript randomly selects cells at intervals and adds a highlight class
- CSS keyframe animations handle the glow-in and fade-out transitions
- A radial gradient mask fades the grid edges for a polished look
Customization
- Adjust
COLS,ROWS,CELL_SIZE, andGAPto change the grid density - Modify the highlight color via the
--glow-colorCSS variable - Control animation speed with
--glow-durationand the JS interval timing
When to use it
- Hero section backgrounds
- Behind pricing or feature cards
- Dashboard ambient backgrounds
- Landing page visual accents