一组网格加载动画

news2024/12/23 12:35:24

先看效果:
在这里插入图片描述
再看代码:

<!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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/650881.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝牙ble的常见概念

蓝牙广播 包组成结构 低功耗蓝牙一共有40个信道&#xff0c;频段范围从2402Mhz-2480Mhz&#xff0c;每2Mhz一个信道&#xff0c;37 38 39 是广播信道&#xff0c;其余为数据信道 一个广播信道最长37字节&#xff0c;有6字节用作蓝牙设备的MAC地址&#xff0c;我们只需要关注剩…

tftp服务器环境搭建与nfs服务器环境搭建

目录 tftp 服务器环境搭建 实验步骤&#xff1a; nfs 服务器环境搭建 实验步骤 tftp 服务器环境搭建 实验步骤&#xff1a; 一、 tftp 服务器环境搭建 1 、 打开一个命令行终端&#xff0c;执行如下命令查看是否已安装 tftp 服务器 $ dpkg -s tftpd-hpa 若显示如下信…

vue可视化面板创建项目

前端项目初始化步骤 安装 vue 脚手架 通过vue脚手架创建项目 在命令行输入vue ui 等待可视化界面打开 填写项目名称&#xff08;必须英文&#xff09;和仓库信息(可选填&#xff09;&#xff0c;然后点击下一步进入“预设面板” 这里根据需要选择一个选项&#xff0c;然后…

Node.js入门之 - 初识Node.js

初识 Node.js 1. 起源 Node.js 起源于 2009 年,由 Ryan Dahl 开发,起初的目的是为了解决一些网络应用运行缓慢的问题。 在 Node.js 之前,一般会采用 LAMP(Linux Apache MySQL PHP)或者 MEAN等技术栈开发 web 应用。这些技术通常会采用请求-响应模型: 客户端(浏览器)发送一…

机器学习 day19(使用python和np实现前向传播)

烤咖啡豆模型 使用一维数组来表示这些向量和参数&#xff0c;所以只有一个方括号W1_1&#xff1a;表示layer 1的第一个神经元的WZ1_1&#xff1a;表示 W1_1和输入X之间的点积&#xff0c;再与b1_1相加a1_1&#xff1a;表示应用Z1_1的sigmoid函数a1&#xff1a;表示把a1_1&…

Explain和索引基本优化示例

一、Explain介绍 1、Explain不用版本的使用 在mysql8.0版本只能用explain&#xff0c;已经弃用了explain extended和explain partitions&#xff0c;用了都会出现语法问题&#xff0c;只能用explain&#xff1b;在explain语句后面加上show warnings;可以查看mysql优化后的语句…

市场·分析

寡头垄断市场 完全竞争市场 完全垄断 垄断竞争 博弈论与寡头竞争理论 寡头市场的特征&#xff1a; 少量的企业竞争策略互动纯寡头 -生产相同产品的企业 -市场上只有一个价格差异化寡头 -生产差异化产品的企业 -价格成为决策变量 博弈论基础 博弈论模型描述个体在知道他所采…

用flex布局实现一个流程设计器

最近接到一个需求&#xff0c;要做一个流程设计的功能&#xff0c;大概长下面这个样子&#xff1a; 支持添加、编辑和删除节点&#xff0c;节点只有四种类型&#xff1a;开始节点、普通节点、分支节点、结束节点。 因为每个节点只有一个进和一个出&#xff0c;且节点不需要支持…

一文扫盲 OA、CRM、ERP、MES、HRM、SCM、WMS、KMS 等B端系统

OA系统 &#xff08;Office Automation System&#xff0c;办公自动化系统&#xff09;&#xff1a;OA系统是一种用于协调、管理和优化办公流程的软件系统&#xff0c;包括电子邮件、日程安排、文档管理、工作流程管理等功能模块&#xff0c;帮助企业提高工作效率和管理水平。…

C#程序的内存映射文件解析

一、背景 前段时间训练营里有朋友问 内存映射文件 是怎么玩的&#xff1f;说实话这东西理论我相信很多朋友都知道&#xff0c;就是将文件映射到进程的虚拟地址&#xff0c;说起来很容易&#xff0c;那如何让大家眼见为实呢&#xff1f;可能会难倒很多人&#xff0c;所以这篇我…

《项目实战》构建SpringCloud alibaba项目

文章目录 1、概要2、整体架构流程2.1、技术结构组成部分 3、技术名词解释4、技术细节4.1、构建父工程4.1.1、选择构建Maven项目4.1.2、修改父工程文件4.1.3、修改父工程pom.xml配置4.1.3.1、添加springboot支持4.1.3.2、修改JDK版本、编码、springboot版本配置4.1.3.3、添加Spr…

自定义MaterialEditText

自定义MaterialEditText 日记 现在都不流行写博客了&#xff0c;因为这玩意都认为对于面试没啥用&#xff0c;我感觉很多事情不应该太功利。所谓博客还是更多的应该用来进行自己日常学习的归纳和总结&#xff0c;而不是去贪图所谓的面试加分。因为面试可能是一时的&#xff0…

Apple Vision Pro的价格并没有看起来那么疯狂

When Apple announced the price of their groundbreaking new mixed reality headset, the Vision Pro, jaws around the world collectively dropped. At a hefty $3,499, it’s not for everyone, but is it really so unreasonable if we take a closer look? 当苹果宣布其…

CSS特性、背景属性和显示模式

CSS特性 CSS特性&#xff1a;化简代码 / 定位问题&#xff0c;并解决问题 继承性层叠性优先级 继承性 继承性&#xff1a;子级默认继承父级的文字控制属性。 注意&#xff1a;如果标签有默认文字样式会继承失败。 例如&#xff1a;a 标签的颜色、标题的字体大小。 层叠性 …

前端 sentry 接入钉钉机器人

sentry 接入钉钉机器人 打开钉钉,添加机器人 此时会得到Webhook地址,记录一下,以后会用到 sentry 端设置 看看这里有木有钉钉插件,有的话开启插件,并配置这里我说一下没有的情况下,我们何如设置 这里需要填写webhook url 这个的url 需要是一个公网的地址,不可以是本地…

HID协议学习

HID协议学习 0. 文档资料 USB_HID协议中文版_USB接口HID设备_AUJsRmB9kg.pdf HID报告描述符精细说明_mgCxM8_ci9.pdf hut1_22_U3cvnwn_ZZ.pdf 1. 基本概念 HID协议是一种基于USB的通讯协议&#xff0c;用于在计算机和输入设备之间进行数据传输。HID协议定义了标准的数据格…

动态规划算法(子数组专题1)

动态规划算法专辑之子数组问题&#xff08;1&#xff09; 本专栏将从状态定义、状态转移方程、初始化、填表顺序、返回值这五大细节来详细讲述动态规划的算法的解题思路及代码实现一、什么是子数组 子数组&#xff1a;子数组是数组中的一个连续部分的集合&#xff0c;子序列可…

Python+Selenium UI自动化测试环境搭建及使用

目录 一、什么是Selenium &#xff1f; 二、Selenium环境搭建 三、WebDriver API 总结&#xff1a; 一、什么是Selenium &#xff1f; Selenium 是一个浏览器自动化测试框架&#xff0c;它主要用于web应用程序的自动化测试&#xff0c;其主要特点如下&#xff1a;开源、免费…

缅怀(上次写博客是2009年10月24日)

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

Nucleo-F411RE (STM32F411)LL库体验 3 - 滴嗒定时器的配置

Nucleo-F411RE &#xff08;STM32F411&#xff09;LL库体验 3 - 滴嗒定时器的配置 1、LL库延时 LL库初始化时钟的时候调用了LL_Init1msTick(100000000)函数&#xff0c;这个函数其实就是初始化了系统的滴答定时器。 LL_InitTick原型如下&#xff1a; load值 sysclk/1000&a…