Retro-futuristic html background

A configurable and animated HTML background, relatively lightweight HTML, JavaScript and embedded CSS. Colors, size, speed et cetera can all be easily configured.

View in full window https://cyberdream.se/abstract/index.htm


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Animated Background</title>
    <style>
        :root {
            --bg-color: #2b2b2b;  /* something very dark */
            --rect-color-1: #8f8f8f;  /* dark gray */
            --rect-color-2: #f7f7f7; /* white ish */
            --rect-color-3: #ffa600; /* orange */
            --rect-shadow: 16px 16px 32px rgba(0, 0, 0, 0.9);
            --min-rect-size: 32%;   /* 30px */
            --max-rect-size: 256%;  /* 100px */
            --num-rects: 32;
            --animation-speed: 512s;
            --speed-variation: 64s;
        }

        body {
            margin: 0;
            background-color: var(--bg-color);
            overflow: hidden;
        }

        .rectangle {
            position: absolute;
            border-radius: 16%;
            box-shadow: var(--rect-shadow);
            opacity: 1;  /* 1 */
        }
    </style>
</head>
<body>
    <script>
        const rootStyles = getComputedStyle(document.documentElement);

        const config = {
            bgColor: rootStyles.getPropertyValue('--bg-color'),
            colors: [
                rootStyles.getPropertyValue('--rect-color-1').trim(),
                rootStyles.getPropertyValue('--rect-color-2').trim(),
                rootStyles.getPropertyValue('--rect-color-3').trim()
            ],
            shadow: rootStyles.getPropertyValue('--rect-shadow').trim(),
            minSize: parseInt(rootStyles.getPropertyValue('--min-rect-size')),
            maxSize: parseInt(rootStyles.getPropertyValue('--max-rect-size')),
            numRects: parseInt(rootStyles.getPropertyValue('--num-rects')),
            animationSpeed: parseFloat(rootStyles.getPropertyValue('--animation-speed')),
            speedVariation: parseFloat(rootStyles.getPropertyValue('--speed-variation')),
        };

        const createRectangle = () => {
            const rect = document.createElement('div');
            const size = Math.random() * (config.maxSize - config.minSize) + config.minSize;

            rect.classList.add('rectangle');
            rect.style.width = `${size}px`;
            rect.style.height = `${size}px`;
            rect.style.backgroundColor = config.colors[Math.floor(Math.random() * config.colors.length)];
            rect.style.left = `${Math.random() * window.innerWidth}px`;
            rect.style.top = `${Math.random() * window.innerHeight}px`;

            const animationDuration = config.animationSpeed + (Math.random() - 0.5) * config.speedVariation;

            rect.style.animation = `move ${Math.abs(animationDuration)}s linear infinite alternate`;
            document.body.appendChild(rect);

            return rect;
        };

        const setKeyframes = () => {
            const styleSheet = document.styleSheets[0];

            for (let i = 0; i < config.numRects; i++) {
                const moveKeyframes = `
                    @keyframes move-${i} {
                        0% {
                            transform: translate(0, 0);
                        }
                        25% {
                            transform: translate(${Math.random() * 200 - 100}px, ${Math.random() * 200 - 100}px);
                        }
                        50% {
                            transform: translate(${Math.random() * 200 - 100}px, ${Math.random() * 200 - 100}px);
                        }
                        75% {
                            transform: translate(${Math.random() * 200 - 100}px, ${Math.random() * 200 - 100}px);
                        }
                        100% {
                            transform: translate(0, 0);
                        }
                    }
                `;
                styleSheet.insertRule(moveKeyframes, styleSheet.cssRules.length);
            }
        };

        const init = () => {
            setKeyframes();

            for (let i = 0; i < config.numRects; i++) {
                const rect = createRectangle();
                rect.style.animationName = `move-${i}`;
            }
        };

        init();

        window.addEventListener('resize', () => {
            document.querySelectorAll('.rectangle').forEach(rect => rect.remove());
            init();
        });
    </script>
</body>
</html>

Post a Reply