一组网格加载动画

先看效果:

再看代码:

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>网格动画title>
    <style>
        @import url("https://fonts.googleapis.com/css2?family=Orbitron&family=Quicksand:wght@300&display=swap");
        html,
        body {
            background-color: #121212;
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            justify-content: center;
            width: 100%;
            font-size: 16px;
            font-weight: bold;
            color: #aaa;
            font-family: "Quicksand", serif;
        }

        @media (max-width: 800px) {
            html,
            body {
                font-size: 13px;
            }
        }
        @media (max-width: 650px) {
            html,
            body {
                font-size: 10px;
            }
        }
        .wrapper {
            display: grid;
            justify-content: center;
            grid-template-columns: repeat(2, 1fr);
            gap: 7rem 5rem;
            margin: 5rem 0;
        }

        @media (max-width: 480px) {
            .wrapper {
                grid-template-columns: repeat(1, 1fr);
            }
        }
        @media (min-width: 1300px) {
            .wrapper {
                grid-template-columns: repeat(3, 1fr);
            }
        }
        .box {
            --box-width: 20rem;
            --box-height: 30rem;
            --frag-width: calc(var(--box-width) / var(--col));
            --frag-height: calc(var(--box-height) / var(--row));
            --img-url: url("https://djjjk9bjm164h.cloudfront.net/leather01.jpg");
            display: flex;
            justify-content: center;
            flex-wrap: wrap;
            width: var(--box-width);
            height: var(--box-height);
            position: relative;
        }

        .box::before {
            content: attr(data-title);
            position: absolute;
            top: calc(100% + 1.5rem);
            font-size: 1.7rem;
        }

        .box::after {
            content: "CLICK ME";
            position: absolute;
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.5rem;
            cursor: pointer;
            color: #aaa;
            background-image: repeating-linear-gradient(-45deg, rgba(100, 100, 100, 0.25), rgba(100, 100, 100, 0.25) 1px, transparent 1px, transparent 6px);
            background-size: 4px 4px;
            transition: all 0.2s;
        }

        .box.hide::after {
            opacity: 0;
        }

        .box.hide:hover::after {
            opacity: 0;
        }

        .box:hover::after {
            background-image: initial;
            font-size: 1.8rem;
        }

        .fragment {
            --x-offset: calc(var(--x) * var(--frag-width) * -1);
            --y-offset: calc(var(--y) * var(--frag-height) * -1);
            --rotateX: rotateX(0);
            --rotateY: rotateY(0);
            width: var(--frag-width);
            height: var(--frag-height);
            background: var(--img-url) var(--x-offset) var(--y-offset)/var(--box-width) var(--box-height) no-repeat;
            backface-visibility: hidden;
            will-change: transform;
            transform: var(--rotateX) var(--rotateY) scale(0.8);
            animation: flip var(--duration) linear var(--delay) forwards;
            opacity: 0;
        }

        @keyframes flip {
            0% {
                transform: var(--rotateX) var(--rotateY) scale(0.8);
                opacity: 0;
            }
            15% {
                transform: var(--rotateX) var(--rotateY) scale(0.8);
                opacity: 0;
            }
            70% {
                transform: rotateX(0) rotateY(0) scale(0.8);
                opacity: 1;
            }
            100% {
                transform: rotateX(0) rotateY(0) scale(1);
                opacity: 1;
            }
        }
    style>
head>
<body>
<div class="wrapper">
    <div class="box" data-i="13" data-title="⇒⊚⇐">div>
    <div class="box" data-i="0" data-title="">div>
    <div class="box" data-i="1" data-title="">div>
    <div class="box" data-i="2" data-title="">div>
    <div class="box" data-i="3" data-title="">div>
    <div class="box" data-i="4" data-title="">div>
    <div class="box" data-i="5" data-title="">div>
    <div class="box" data-i="6" data-title="">div>
    <div class="box" data-i="7" data-title="↖↘">div>
    <div class="box" data-i="8" data-title="↘↖">div>
    <div class="box" data-i="9" data-title="">div>
    <div class="box" data-i="10" data-title="↙↗">div>
    <div class="box" data-i="11" data-title="↗↙">div>
    <div class="box" data-i="12" data-title="⇐⊚⇒">div>
div>
body>
<script>
    class GridAnimation {
        constructor(el, row = 13, col = 9) {
            this.element = el;
            this.fragments = el.children;
            this.row = row;
            this.col = col;
            this.duration = 2000;
            this.delayDelta = 70;
            this.type = null;

            this.randomIntBetween = (min, max) => {
                return Math.floor(Math.random() * (max - min + 1) + min);
            };

            this.element.style.setProperty("--row", this.row);
            this.element.style.setProperty("--col", this.col);
            this.element.addEventListener("click", this.trigger);
        }

        trigger = () => {
            if (this.fragments.length > 0) this.clear();
            this.element.classList.add("hide");
            this.animate();
        };

        setType = (type) => {
            this.type = type;
        };

        clear = () => {
            while (this.element.hasChildNodes()) {
                this.element.removeChild(this.element.firstChild);
            }
        };

        animate = () => {
            if (this.type === null) return;
            const x = this.col - 1;
            const y = this.row - 1;
            for (let i = 0; i < this.row; i++) {
                for (let j = 0; j < this.col; j++) {
                    const fragment = document.createElement("div");
                    fragment.className = "fragment";
                    fragment.style.setProperty("--x", j);
                    fragment.style.setProperty("--y", i);

                    let delay = 0;
                    switch (this.type) {
                        case 0:
                            delay = i * 2;
                            break;
                        case 1:
                            delay = j * 2;
                            break;
                        case 2:
                            delay = this.randomIntBetween(0, x + y);
                            break;
                        case 3:
                            delay = x + y - (j + i);
                            break;
                        case 4:
                            delay = i + j;
                            break;
                        case 5:
                            delay = x - i + j;
                            break;
                        case 6:
                            delay = i + (y - j);
                            break;
                        case 7:
                            delay = Math.abs((x + y) / 2 - (j + i));
                            break;
                        case 8:
                            delay = (x + y) / 2 - Math.abs((x + y) / 2 - (j + i));
                            break;
                        case 9:
                            delay =
                                (x + y) / 2 - Math.abs((x + y) / 2 - (j + i)) * Math.cos(i + j);
                            break;
                        case 10:
                            delay = Math.abs((x + y) / 2 - (x - j + i));
                            break;
                        case 11:
                            delay = Math.abs((x + y) / 2 - Math.abs((x + y) / 2 - (x - j + i)));
                            break;
                        case 12:
                            delay = Math.abs(x / 2 - j) + Math.abs(y / 2 - i);
                            break;
                        case 13:
                            delay = x / 2 - Math.abs(x / 2 - j) + (x / 2 - Math.abs(y / 2 - i));
                            break;
                    }

                    const isOdd = (i + j) % 2 === 0;
                    fragment.style.setProperty(
                        "--rotateX",
                        `rotateX(${isOdd ? -180 : 0}deg)`
                    );
                    fragment.style.setProperty(
                        "--rotateY",
                        `rotateY(${isOdd ? 0 : -180}deg)`
                    );
                    fragment.style.setProperty("--delay", delay * this.delayDelta + "ms");
                    fragment.style.setProperty("--duration", this.duration + "ms");
                    this.element.appendChild(fragment);

                    const timer = setTimeout(() => {
                        fragment.style.willChange = "initial";
                        fragment.style.transform = "initial";
                        fragment.style.animation = "initial";
                        fragment.style.backfaceVisibility = "initial";
                        fragment.style.opacity = 1;
                        clearTimeout(timer);
                    }, this.duration + delay * this.delayDelta);
                }
            }
        };
    }

    document.querySelectorAll(".box").forEach((box, index) => {
        const gridAnimation = new GridAnimation(box);
        const type = parseInt(box.getAttribute("data-i"));
        gridAnimation.setType(type);
        if (index === 0) gridAnimation.trigger();
    });

script>
html>

你可能感兴趣的:(CSS,javascript,css,css3,html)