眼睛:来一场视觉盛宴《手拿把掐》css特效 —— 之听说过CSS【笑】

news2024/11/24 10:29:27

😷😊🤺🤺🤺前期回顾f8e3cc1a0f694ac2b665ca2ad14c49d7.png

打造极简风格动效 —— 5 分钟轻松实现惊艳、震撼人心的视觉效果_彩色之外的博客-CSDN博客

😁

css动画 —— 把你喜欢css动画嵌入到浏览器中_css做的动画效果怎么嵌入网页_彩色之外的博客-CSDN博客

 代码已上传资源

  开头省略200字》……
念及此
  直接上图

目录

😊 进度条

🥰 唯美登录背景

 😎 蜡烛登录动画

🥵 火箭 

😶‍🌫️ 时间翻盘

🤺 复选框动画

🤪 基础表单输入动画

😃 卡包动画

😷 流光扫过动画

🥶 酷炫标题

🤖 交互式评分

🐔 动态向上箭头

 🐽 卸载对话框表情交互动画

 ✈️ 随机密码生成器代码

🧨 跟随设备切换主题

🚒 昼夜切换主题

 ❤️‍🩹 使用系统取色器

😃 右键动态菜单(已做边缘动画及边界外判断)

🎋 酷炫打字特效

🚆 方形抽奖

🚼 圆形抽奖

🛹 吸顶楼层导航

✈️ 困了盖坤

🛫 扣扣乐

🍰 签名回溯

🌍 翻盘抽奖

🪂 地址 🤺🤺🤺 

 🥰😉  谢谢观看


 

 图例:

  图片过多,不在开头一一展示了,下面图与源码会放在一起,代码设计原生JS、VUE3

😊 进度条

<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title>3款漂亮的html5+css3 3D百分比进度条动画特效</title>

  <style>
    @import url("https://fonts.googleapis.com/css?family=Nunito:400,900");

    * {
      box-sizing: border-box;
    }

    body,
    html {
      font-family: "Nunito", sans-serif;
      background: linear-gradient(0deg, #EEEFED, #F9E3E9);
      margin: 0;
      padding: 0;
      color: #4D5075;
      font-weight: 300;
      width: 100%;
      height: 100%;
      margin: 0;
    }

    body {
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      padding: 7vh 15vw 0vh 15vw;
    }

    h1 {
      text-align: center;
      margin: 0 0 10vh 0;
      font-size: 7vh;
      font-weight: 500;
      text-shadow: 0px -15px 70px rgba(77, 80, 117, 0.6);
    }

    h1 b {
      font-weight: 900;
    }

    p {
      text-align: center;
      font-size: 1.3rem;
      text-shadow: 10px 5px 25px rgba(77, 80, 117, 0.6);
      margin-bottom: 8vh;
    }

    .third-bar-p {
      margin-top: 7vh;
    }

    .perspective {
      -webkit-perspective: 70vh;
      perspective: 70vh;
      text-align: center;
      -webkit-perspective-origin: 50% 50%;
      perspective-origin: 50% 50%;
      position: relative;
      transition: -webkit-transform 0.3s ease;
      transition: transform 0.3s ease;
      transition: transform 0.3s ease, -webkit-transform 0.3s ease;
    }

    .perspective:hover {
      -webkit-transform: scale(1.04);
      transform: scale(1.04);
    }

    .bar-input {
      position: absolute;
      height: 100%;
      left: 0;
      right: 0;
      margin: auto;
      opacity: 0;
    }

    #first-bar .bar-input {
      width: 55vh;
    }

    #second-bar .bar-input {
      width: 40vh;
    }

    #third-bar .bar-input {
      width: 42vh;
    }

    .bar {
      display: inline-block;
      position: relative;
      -webkit-transform: rotateX(55deg);
      transform: rotateX(55deg);
      -webkit-transform-style: preserve-3d;
      transform-style: preserve-3d;
    }

    .bar .bar-face {
      display: inline-block;
      width: 100%;
      height: 100%;
      position: absolute;
      left: 0;
      -webkit-transform-origin: 50% 100%;
      transform-origin: 50% 100%;
    }

    .bar .bar-face.front {
      -webkit-transform: rotateX(-90deg);
      transform: rotateX(-90deg);
    }

    .bar .bar-face.percentage:before {
      height: 100%;
      content: "";
      display: block;
      position: absolute;
      bottom: 0;
      margin: 0;
    }

    #first-bar .bar {
      width: 55vh;
      height: 7vh;
    }

    #first-bar .bar .bar-face {
      background: rgba(255, 255, 255, 0.5);
    }

    #first-bar .bar .bar-face.floor {
      box-shadow: 0 1.3em 1.2em -0.4em rgba(0, 0, 70, 0.25), 0 -2em 15em 0.5em #4d5075, 0 -0.75em 25em 10em rgba(255, 255, 255, 0.4);
    }

    #first-bar .bar .bar-face.percentage:before {
      box-shadow: 0 1.6em 7em -0.3em rgba(149, 65, 105, 0.5);
    }

    #first-bar .bar .bar-face.roof {
      -webkit-transform: translateZ(7vh);
      transform: translateZ(7vh);
    }

    #first-bar .bar .bar-face.back {
      -webkit-transform: rotateX(-90deg) translateZ(-7vh);
      transform: rotateX(-90deg) translateZ(-7vh);
    }

    #first-bar .bar .bar-face.percentage:before {
      background-color: rgba(149, 65, 105, 0.6);
    }

    #second-bar .bar {
      width: 40vh;
      height: 10vh;
    }

    #second-bar .bar .bar-face {
      background: rgba(60, 75, 132, 0.5);
      background-image: linear-gradient(90deg, rgba(134, 114, 146, 0.5), rgba(60, 75, 132, 0.1)), url("https://zephyo.github.io/22Days/code/5/graphics/stars.svg"), url("https://zephyo.github.io/22Days/code/5/graphics/stars2.svg");
      background-repeat: repeat repeat;
    }

    #second-bar .bar .bar-face.floor {
      box-shadow: 0 1.3em 1.2em -0.4em rgba(0, 0, 70, 0.25), 0 -2em 15em 0.5em #4d5075, 0 -0.75em 25em 10em rgba(255, 255, 255, 0.4);
    }

    #second-bar .bar .bar-face.percentage:before {
      box-shadow: 0 1.6em 7em -0.3em rgba(200, 212, 250, 0.5);
    }

    #second-bar .bar .bar-face.roof {
      -webkit-transform: translateZ(10vh);
      transform: translateZ(10vh);
    }

    #second-bar .bar .bar-face.back {
      -webkit-transform: rotateX(-90deg) translateZ(-10vh);
      transform: rotateX(-90deg) translateZ(-10vh);
    }

    #second-bar .bar .bar-face.percentage:before {
      background-image: url("https://zephyo.github.io/22Days/code/5/graphics/sky.png");
      opacity: 0.9;
    }

    #third-bar .bar {
      width: 42vh;
      height: 8vh;
    }

    #third-bar .bar .bar-face {
      background: rgba(232, 154, 173, 0.7);
    }

    #third-bar .bar .bar-face.floor {
      box-shadow: 0 1.3em 1.2em -0.4em rgba(0, 0, 70, 0.25), 0 -2em 15em 0.5em #4d5075, 0 -0.75em 25em 10em rgba(255, 255, 255, 0.4);
    }

    #third-bar .bar .bar-face.percentage:before {
      box-shadow: 0 1.6em 7em -0.3em rgba(236, 0, 113, 0.5);
    }

    #third-bar .bar .bar-face.roof {
      -webkit-transform: translateZ(8vh);
      transform: translateZ(8vh);
    }

    #third-bar .bar .bar-face.back {
      -webkit-transform: rotateX(-90deg) translateZ(-8vh);
      transform: rotateX(-90deg) translateZ(-8vh);
    }

    #third-bar .bar .bar-face.percentage:before {
      background: linear-gradient(90deg, rgba(245, 239, 200, 0.5), #ec0071);
    }

    #third-bar .bar .indicator {
      box-shadow: 0px 15px 35px rgba(236, 0, 113, 0.3);
      background: #ec0071;
      width: 8vh;
      height: 8vh;
      color: white;
      -webkit-transform: translateY(9.6vh);
      transform: translateY(9.6vh);
      text-align: center;
      font-size: 2.5vh;
      font-weight: 900;
      line-height: 8vh;
    }

    #third-bar .bar .indicator:before {
      content: "";
      position: absolute;
      background: #ec0071;
      left: 0;
      right: 0;
      margin: auto;
      top: -6px;
      width: 4vh;
      height: 4vh;
      z-index: -1;
      -webkit-transform: rotate(45deg);
      transform: rotate(45deg);
    }
  </style>

</head>

<body>
  <script src="/demos/googlegg.js"></script>

  <h1>Scalable <b>3D</b> Range Sliders</h1>

  <main class="perspective" id="first-bar">
    <section class="bar">
      <div class="bar-face back percentage"></div>
      <div class="bar-face floor percentage"></div>
      <div class="bar-face roof percentage"></div>
      <div class="bar-face front percentage"></div>
    </section>
    <input class="bar-input" type="range" min="0" max="101" value="64" />
  </main>
  <p>Simple Range</p>


  <main class="perspective" id="second-bar">
    <section class="bar">
      <div class="bar-face back percentage"></div>
      <div class="bar-face floor percentage"></div>
      <div class="bar-face roof percentage"></div>
      <div class="bar-face front percentage"></div>
    </section>
    <input class="bar-input" type="range" min="0" max="101" value="37" />
  </main>
  <p>Patterned Range</p>


  <main class="perspective" id="third-bar">
    <section class="bar">
      <div class="bar-face back percentage"></div>
      <div class="bar-face floor percentage"></div>
      <div class="bar-face roof percentage"></div>
      <div class="bar-face front percentage"></div>
      <div class="indicator">89%</div>
    </section>
    <input class="bar-input" type="range" min="0" max="100" value="89" />
  </main>
  <p class="third-bar-p">Gradient Range with Indicator</p>

  <script>
    function initInputs() {
      var allInputs = document.body.querySelectorAll(".bar-input");

      for (var i = 0; i < allInputs.length; i++) {
        var input = allInputs[i];
        var barId = input.parentNode.id;
        var styleEl = document.head.appendChild(document.createElement("style"));

        if (i == allInputs.length - 1) {
          //set indicator
          var indicator = input.parentNode.querySelector('.bar .indicator');
          setBarIndicator(barId, input, styleEl, indicator);
          input.oninput = setBarIndicator.bind(this, barId, input, styleEl, indicator);
          input.onchange = setBarIndicator.bind(this, barId, input, styleEl, indicator);
        } else {
          setBar(barId, input, styleEl);
          input.oninput = setBar.bind(this, barId, input, styleEl);
          input.onchange = setBar.bind(this, barId, input, styleEl);
        }
      }
    }

    function setBar(barId, input, styleEl) {
      styleEl.innerHTML =
        "#" + barId + " .bar-face.percentage:before {width:" + input.value + "%;}";
    }

    function setBarIndicator(barId, input, styleEl, indicatorEl) {
      styleEl.innerHTML =
        "#" + barId + " .bar-face.percentage:before {width:" + input.value + "%;}";
      indicatorEl.style.marginLeft = (input.value - 10) + '%';
      indicatorEl.textContent = input.value + '%';
    }

    initInputs();
  </script>

  </div>
</body>

</html>

🥰 唯美登录背景

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>HTML5 Canvas透明丝带飘动背景动画特效</title>

    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            background-color: #000;
            overflow: hidden;
        }

        .login-container {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }
    </style>

</head>

<body>

    <div class="login-container"></div>

    <script>
        (function () {

            let pi = Math.PI;
            let pi2 = 2 * Math.PI;

            this.Waves = function (holder, options) {
                let Waves = this;

                Waves.options = extend(options || {}, {
                    resize: false,
                    rotation: 45,
                    waves: 5,
                    width: 100,
                    hue: [11, 14],
                    amplitude: 0.5,
                    background: true,
                    preload: true,
                    speed: [0.004, 0.008],
                    debug: false,
                    fps: false,
                });

                Waves.waves = [];

                Waves.holder = document.querySelector('.login-container');
                Waves.canvas = document.createElement('canvas');
                Waves.ctx = Waves.canvas.getContext('2d');
                Waves.holder.appendChild(Waves.canvas);

                Waves.hue = Waves.options.hue[0];
                Waves.hueFw = true;
                Waves.stats = new Stats();

                Waves.resize();
                Waves.init(Waves.options.preload);

                if (Waves.options.resize)
                    window.addEventListener('resize', function () {
                        Waves.resize();
                    }, false);

            };

            Waves.prototype.init = function (preload) {
                let Waves = this;
                let options = Waves.options;

                for (let i = 0; i < options.waves; i++)
                    Waves.waves[i] = new Wave(Waves);

                if (preload) Waves.preload();
            };

            Waves.prototype.preload = function () {
                let Waves = this;
                let options = Waves.options;

                for (let i = 0; i < options.waves; i++) {
                    Waves.updateColor();
                    for (let j = 0; j < options.width; j++) {
                        Waves.waves[i].update();
                    }
                }
            };

            Waves.prototype.render = function () {
                let Waves = this;
                let ctx = Waves.ctx;
                let options = Waves.options;

                Waves.updateColor();
                Waves.clear();

                if (Waves.options.debug) {
                    ctx.beginPath();
                    ctx.strokeStyle = '#f00';
                    ctx.arc(Waves.centerX, Waves.centerY, Waves.radius, 0, pi2);
                    ctx.stroke();
                }

                if (Waves.options.background) {
                    Waves.background();
                }

                each(Waves.waves, function (wave, i) {
                    wave.update();
                    wave.draw();
                });
            };

            Waves.prototype.animate = function () {
                let Waves = this;

                Waves.render();

                // if (Waves.options.fps) {
                //   Waves.stats.log();
                //   Waves.ctx.font = '12px Arial';
                //   Waves.ctx.fillStyle = '#fff';
                //   Waves.ctx.fillText(Waves.stats.fps() + ' FPS', 10, 22);
                // }

                window.requestAnimationFrame(Waves.animate.bind(Waves));
            };

            Waves.prototype.clear = function () {
                let Waves = this;
                Waves.ctx.clearRect(0, 0, Waves.width, Waves.height);
            };

            Waves.prototype.background = function () {
                let Waves = this;
                let ctx = Waves.ctx;

                let gradient = Waves.ctx.createLinearGradient(0, 0, 0, Waves.height);
                gradient.addColorStop(0, '#000');
                gradient.addColorStop(1, Waves.color);

                ctx.fillStyle = gradient;
                ctx.fillRect(0, 0, Waves.width, Waves.height);
            };

            Waves.prototype.resize = function () {
                let Waves = this;
                let width = Waves.holder.offsetWidth;
                let height = Waves.holder.offsetHeight;
                Waves.scale = window.devicePixelRatio || 1;
                Waves.width = width * Waves.scale;
                Waves.height = height * Waves.scale;
                Waves.canvas.width = Waves.width;
                Waves.canvas.height = Waves.height;
                Waves.canvas.style.width = width + 'px';
                Waves.canvas.style.height = height + 'px';
                Waves.radius = Math.sqrt(Math.pow(Waves.width, 2) + Math.pow(Waves.height, 2)) / 2;
                Waves.centerX = Waves.width / 2;
                Waves.centerY = Waves.height / 2;
                //Waves.radius /= 2; // REMOVE FOR FULLSREEN
            };

            Waves.prototype.updateColor = function () {
                let Waves = this;

                Waves.hue += (Waves.hueFw) ? 0.01 : -0.01;

                if (Waves.hue > Waves.options.hue[1] && Waves.hueFw) {
                    Waves.hue = Waves.options.hue[1];
                    Waves.Waves = false;
                } else if (Waves.hue < Waves.options.hue[0] && !Waves.hueFw) {
                    Waves.hue = Waves.options.hue[0];
                    Waves.Waves = true;
                }

                let a = Math.floor(127 * Math.sin(0.3 * Waves.hue + 0) + 128);
                let b = Math.floor(127 * Math.sin(0.3 * Waves.hue + 2) + 128);
                let c = Math.floor(127 * Math.sin(0.3 * Waves.hue + 4) + 128);

                Waves.color = 'rgba(' + a + ',' + b + ',' + c + ', 0.1)';
            };

            function Wave(Waves) {
                let Wave = this;
                let speed = Waves.options.speed;

                Wave.Waves = Waves;
                Wave.Lines = [];

                Wave.angle = [
                    rnd(pi2),
                    rnd(pi2),
                    rnd(pi2),
                    rnd(pi2)
                ];

                Wave.speed = [
                    rnd(speed[0], speed[1]) * rnd_sign(),
                    rnd(speed[0], speed[1]) * rnd_sign(),
                    rnd(speed[0], speed[1]) * rnd_sign(),
                    rnd(speed[0], speed[1]) * rnd_sign(),
                ];

                return Wave;
            }

            Wave.prototype.update = function () {
                let Wave = this;
                let Lines = Wave.Lines;
                let color = Wave.Waves.color;

                Lines.push(new Line(Wave, color));

                if (Lines.length > Wave.Waves.options.width) {
                    Lines.shift();
                }
            };

            Wave.prototype.draw = function () {
                let Wave = this;
                let Waves = Wave.Waves;

                let ctx = Waves.ctx;
                let radius = Waves.radius;
                let radius3 = radius / 3;
                let x = Waves.centerX;
                let y = Waves.centerY;
                let rotation = dtr(Waves.options.rotation);
                let amplitude = Waves.options.amplitude;
                let debug = Waves.options.debug;

                let Lines = Wave.Lines;

                each(Lines, function (line, i) {
                    if (debug && i > 0) return;

                    let angle = line.angle;

                    let x1 = x - radius * Math.cos(angle[0] * amplitude + rotation);
                    let y1 = y - radius * Math.sin(angle[0] * amplitude + rotation);
                    let x2 = x + radius * Math.cos(angle[3] * amplitude + rotation);
                    let y2 = y + radius * Math.sin(angle[3] * amplitude + rotation);
                    let cpx1 = x - radius3 * Math.cos(angle[1] * amplitude * 2);
                    let cpy1 = y - radius3 * Math.sin(angle[1] * amplitude * 2);
                    let cpx2 = x + radius3 * Math.cos(angle[2] * amplitude * 2);
                    let cpy2 = y + radius3 * Math.sin(angle[2] * amplitude * 2);

                    ctx.strokeStyle = (debug) ? '#fff' : line.color;

                    ctx.beginPath();
                    ctx.moveTo(x1, y1);
                    ctx.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x2, y2);
                    ctx.stroke();

                    if (debug) {
                        ctx.strokeStyle = '#fff';
                        ctx.globalAlpha = 0.3;

                        ctx.beginPath();
                        ctx.moveTo(x1, y1);
                        ctx.lineTo(cpx1, cpy1);
                        ctx.stroke();
                        ctx.beginPath();
                        ctx.moveTo(x2, y2);
                        ctx.lineTo(cpx2, cpy2);
                        ctx.stroke();

                        ctx.globalAlpha = 1;
                    }
                });
            };

            function Line(Wave, color) {
                let Line = this;

                let angle = Wave.angle;
                let speed = Wave.speed;

                Line.angle = [
                    Math.sin(angle[0] += speed[0]),
                    Math.sin(angle[1] += speed[1]),
                    Math.sin(angle[2] += speed[2]),
                    Math.sin(angle[3] += speed[3])
                ];

                Line.color = color;
            }

            function Stats() {
                this.data = [];
            }

            Stats.prototype.time = function () {
                return (performance || Date)
                    .now();
            };

            Stats.prototype.log = function () {
                if (!this.last) {
                    this.last = this.time();
                    return 0;
                }

                this.new = this.time();
                this.delta = this.new - this.last;
                this.last = this.new;

                this.data.push(this.delta);
                if (this.data.length > 10)
                    this.data.shift();
            };

            Stats.prototype.fps = function () {
                let fps = 0;
                each(this.data, function (data, i) {
                    fps += data;
                });

                return Math.round(1000 / (fps / this.data.length));
            };

            function each(items, callback) {
                for (let i = 0; i < items.length; i++) {
                    callback(items[i], i);
                }
            }

            function extend(options, defaults) {
                for (let key in options)
                    if (defaults.hasOwnProperty(key))
                        defaults[key] = options[key];
                return defaults;
            }

            function dtr(deg) {
                return deg * pi / 180;
            }

            function rtd(rad) {
                return rad * 180 / pi;
            }

            function diagonal_angle(w, h) {
                let a = Math.atan2(h, w) * 1.27325;
                return a;
            }

            function rnd(a, b) {
                if (arguments.length == 1)
                    return Math.random() * a;
                return a + Math.random() * (b - a);
            }

            function rnd_sign() {
                return (Math.random() > 0.5) ? 1 : -1;
            }

        })();

        let waves = new Waves('.login-container ', {
            fps: true,
            waves: 3,
            width: 200,
        });

        waves.animate();
    </script>

</body>

</html>

 😎 蜡烛登录动画

<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title>CSS3可爱卡通蜡烛交互式动画特效</title>

  <style>
    body {
      background: #13b280;
      /* 背景 */
      animation: change-background 5s infinite linear;
    }

    .wrapper {
      position: absolute;
      left: 80%;
      top: 70%;
      transform: scale(1.5, 1.5) translate(-50%, -50%);
    }

    .floor {
      position: absolute;
      left: 50%;
      top: 50%;
      width: 350px;
      height: 5px;
      background: #673C63;
      transform: translate(-50%, -50%);
      box-shadow: 0px 2px 5px #111;
      z-index: 2;
    }

    .candles {
      position: absolute;
      left: 50%;
      top: 50%;
      width: 250px;
      height: 150px;
      transform: translate(-50%, -100%);
      z-index: 1;
    }

    .candle1 {
      position: absolute;
      left: 50%;
      top: 50%;
      width: 35px;
      height: 100px;
      background: #fff;
      border: 3px solid #673C63;
      border-bottom: 0px;
      border-radius: 3px;
      transform-origin: center right;
      transform: translate(60%, -25%);
      box-shadow: -2px 0px 0px #95c6f2 inset;
      /* 高蜡烛向上伸展动画 */
      animation: expand-body 5s infinite linear;
    }

    .candle1__stick,
    .candle2__stick {
      position: absolute;
      left: 50%;
      top: 0%;
      width: 3px;
      height: 15px;
      background: #673C63;
      border-radius: 8px;
      transform: translate(-50%, -100%);
    }

    .candle2__stick {
      height: 12px;
      transform-origin: bottom center;
      /* 蜡烛芯 */
      animation: stick-animation 5s infinite linear;
    }

    .candle1__eyes,
    .candle2__eyes {
      position: absolute;
      left: 50%;
      top: 0%;
      width: 35px;
      height: 30px;
      transform: translate(-50%, 0%);
    }

    .candle1__eyes-one {
      position: absolute;
      left: 30%;
      top: 20%;
      width: 5px;
      height: 5px;
      border-radius: 100%;
      background: #673C63;
      transform: translate(-70%, 0%);
      /* 高蜡烛眼睛 */
      animation: blink-eyes 5s infinite linear;
    }

    .candle1__eyes-two {
      position: absolute;
      left: 70%;
      top: 20%;
      width: 5px;
      height: 5px;
      border-radius: 100%;
      background: #673C63;
      transform: translate(-70%, 0%);
      /* 高蜡烛眼睛 */
      animation: blink-eyes 5s infinite linear;
    }

    .candle1__mouth {
      position: absolute;
      left: 40%;
      top: 20%;
      width: 0px;
      height: 0px;
      border-radius: 20px;
      background: #673C63;
      transform: translate(-50%, -50%);
      /* 高蜡烛嘴吹气 */
      animation: uff 5s infinite linear;
    }

    .candle__smoke-one {
      position: absolute;
      left: 30%;
      top: 50%;
      width: 30px;
      height: 3px;
      background: grey;
      transform: translate(-50%, -50%);
      /* 气体动画 向左*/
      animation: move-left 5s infinite linear;
    }

    .candle__smoke-two {
      position: absolute;
      left: 30%;
      top: 40%;
      width: 10px;
      height: 10px;
      border-radius: 10px;
      background: grey;
      transform: translate(-50%, -50%);
      /* 气体动画 向上 */
      animation: move-top 5s infinite linear;
    }

    .candle2 {
      position: absolute;
      left: 20%;
      top: 65%;
      width: 42px;
      height: 60px;
      background: #fff;
      border: 3px solid #673C63;
      border-bottom: 0px;
      border-radius: 3px;
      transform: translate(60%, -15%);
      transform-origin: center right;
      box-shadow: -2px 0px 0px #95c6f2 inset;
      /* 矮蜡烛 涨红脸 */
      animation: shake-left 5s infinite linear;
    }

    .candle2__eyes-one {
      position: absolute;
      left: 30%;
      top: 50%;
      width: 5px;
      height: 5px;
      display: inline-block;
      border: 0px solid #673C63;
      border-radius: 100%;
      float: left;
      background: #673C63;
      transform: translate(-80%, 0%);
      /* 矮蜡烛 眼睛 */
      animation: changeto-lower 5s infinite linear;
    }

    .candle2__eyes-two {
      position: absolute;
      left: 70%;
      top: 50%;
      width: 5px;
      height: 5px;
      display: inline-block;
      border: 0px solid #673C63;
      border-radius: 100%;
      float: left;
      background: #673C63;
      transform: translate(-80%, 0%);
      /* 矮蜡烛眼睛 */
      animation: changeto-greater 5s infinite linear;
    }

    .light__wave {
      position: absolute;
      top: 35%;
      left: 35%;
      width: 75px;
      height: 75px;
      border-radius: 100%;
      z-index: 0;
      transform: translate(-25%, -50%) scale(2.5, 2.5);
      border: 2px solid rgba(255, 255, 255, 0.2);
      /* 高蜡烛 向上伸张 */
      animation: expand-light 5s infinite linear;
    }

    .candle2__fire {
      position: absolute;
      top: 50%;
      left: 40%;
      display: block;
      width: 16px;
      height: 20px;
      background-color: red;
      border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
      background: #FF9800;
      transform: translate(-50%, -50%);
      /* 火焰 */
      animation: dance-fire 5s infinite linear;
    }

    @keyframes blink-eyes {

      0%,
      35% {
        opacity: 1;
        transform: translate(-70%, 0%);
      }

      36%,
      39% {
        opacity: 0;
        transform: translate(-70%, 0%);
      }

      40% {
        opacity: 1;
        transform: translate(-70%, 0%);
      }

      50%,
      65% {
        transform: translate(-140%, 0%);
      }

      66% {
        transform: translate(-70%, 0%);
      }
    }

    @keyframes expand-body {

      0%,
      40% {
        transform: scale(1, 1) translate(60%, -25%);
      }

      45%,
      55% {
        transform: scale(1.1, 1.1) translate(60%, -28%);
      }

      60% {
        transform: scale(0.89, 0.89) translate(60%, -25%);
      }

      65% {
        transform: scale(1, 1) translate(60%, -25%);
      }

      70% {
        transform: scale(0.95, 0.95) translate(60%, -25%);
      }

      75% {
        transform: scale(1, 1) translate(60%, -25%);
      }
    }

    @keyframes uff {

      0%,
      40% {
        width: 0px;
        height: 0px;
      }

      50%,
      54% {
        width: 15px;
        height: 15px;
        left: 30%;
      }

      59% {
        width: 5px;
        height: 5px;
        left: 20%;
      }

      62% {
        width: 2px;
        height: 2px;
        left: 20%;
      }

      67% {
        width: 0px;
        height: 0px;
        left: 30%;
      }
    }

    @keyframes change-background {

      0%,
      59%,
      98%,
      100% {
        background: #13b280;
      }

      61%,
      97% {
        background: #F8AE39;
      }
    }

    @keyframes move-left {

      0%,
      59%,
      100% {
        width: 0px;
        left: 40%;
      }

      60% {
        width: 30px;
        left: 30%;
      }

      68% {
        width: 0px;
        left: 20%;
      }
    }

    @keyframes move-top {

      0%,
      64%,
      100% {
        width: 0px;
        height: 0px;
        top: 0%;
      }

      65% {
        width: 10px;
        height: 10px;
        top: 40%;
        left: 40%;
      }

      80% {
        width: 0px;
        height: 0px;
        top: 20%;
      }
    }

    @keyframes shake-left {

      0%,
      40% {
        left: 20%;
        transform: translate(60%, -15%);
      }

      50%,
      54% {
        left: 20%;
        transform: translate(60%, -15%);
      }

      59% {
        left: 20%;
        transform: translate(60%, -15%);
      }

      62% {
        left: 18%;
        transform: translate(60%, -15%);
      }

      65% {
        left: 21%;
        transform: translate(60%, -15%);
      }

      67% {
        left: 20%;
        transform: translate(60%, -15%);
      }

      75% {
        left: 20%;
        transform: scale(1.15, 0.85) translate(60%, -15%);
        background: #fff;
        border-color: #673C63;
      }

      91% {
        left: 20%;
        transform: scale(1.18, 0.82) translate(60%, -10%);
        background: #F44336;
        border-color: #F44336;
        box-shadow: -2px 0px 0px #F44336 inset;
      }

      92% {
        left: 20%;
        transform: scale(0.85, 1.15) translate(60%, -15%);
      }

      95% {
        left: 20%;
        transform: scale(1.05, 0.95) translate(60%, -15%);
      }

      97% {
        left: 20%;
        transform: scale(1, 1) translate(60%, -15%);
      }
    }

    @keyframes stick-animation {

      0%,
      40% {
        left: 50%;
        top: 0%;
        transform: translate(-50%, -100%);
      }

      50%,
      54% {
        left: 50%;
        top: 0%;
        transform: translate(-50%, -100%);
      }

      59% {
        left: 50%;
        top: 0%;
        transform: translate(-50%, -100%);
      }

      62% {
        left: 50%;
        top: 0%;
        transform: rotateZ(-15deg) translate(-50%, -100%);
      }

      65% {
        left: 50%;
        top: 0%;
        transform: rotateZ(15deg) translate(-50%, -100%);
      }

      70% {
        left: 50%;
        top: 0%;
        transform: rotateZ(-5deg) translate(-50%, -100%);
      }

      72% {
        left: 50%;
        top: 0%;
        transform: rotateZ(5deg) translate(-50%, -100%);
      }

      74%,
      84% {
        left: 50%;
        top: 0%;
        transform: rotateZ(0deg) translate(-50%, -100%);
      }

      85% {
        transform: rotateZ(180deg) translate(0%, 120%);
      }

      92% {
        left: 50%;
        top: 0%;
        transform: translate(-50%, -100%);
      }
    }

    @keyframes expand-light {

      10%,
      29%,
      59%,
      89% {
        transform: translate(-25%, -50%) scale(0, 0);
        border: 2px solid rgba(255, 255, 255, 0);
      }

      90%,
      20%,
      50% {
        transform: translate(-25%, -50%) scale(1, 1);
      }

      95%,
      96%,
      26%,
      27%,
      56%,
      57% {
        transform: translate(-25%, -50%) scale(2, 2);
        border: 2px solid rgba(255, 255, 255, 0.5);
      }

      0%,
      28%,
      58%,
      100% {
        transform: translate(-25%, -50%) scale(2.5, 2.5);
        border: 2px solid rgba(255, 255, 255, 0.2);
      }
    }

    @keyframes dance-fire {

      59%,
      89% {
        left: 40%;
        width: 0px;
        height: 0px;
      }

      90%,
      0%,
      7%,
      15%,
      23%,
      31%,
      39%,
      47%,
      55% {
        left: 40.8%;
        width: 16px;
        height: 20px;
        background: #FFC107;
      }

      94%,
      3%,
      11%,
      19%,
      27%,
      35%,
      43%,
      51%,
      58% {
        left: 41.2%;
        width: 16px;
        height: 20px;
        background: #FF9800;
      }
    }

    @keyframes changeto-lower {

      0%,
      70%,
      90% {
        padding: 0px;
        display: inline-block;
        border-radius: 100%;
        background: #673C63;
        border-width: 0 0 0 0;
        border: 0px solid #673C63;
        transform: translate(-90%, 0%);
      }

      71%,
      89% {
        background: none;
        border: solid #673C63;
        border-radius: 0px;
        border-width: 0 2px 2px 0;
        display: inline-block;
        padding: 1px;
        float: left;
        transform-origin: bottom left;
        transform: rotate(-45deg) translate(-50%, -65%);
        -webkit-transform: rotate(-45deg) translate(-50%, -65%);
      }
    }

    @keyframes changeto-greater {

      0%,
      70%,
      90% {
        top: 50%;
        padding: 0px;
        display: inline-block;
        border-radius: 100%;
        background: #673C63;
        border-width: 0 0 0 0;
        border: 0px solid #673C63;
        transform: translate(-80%, 0%);
      }

      71%,
      89% {
        top: 30%;
        background: none;
        border: solid #673C63;
        border-radius: 0px;
        border-width: 0 2px 2px 0;
        display: inline-block;
        padding: 1px;
        float: left;
        transform-origin: bottom left;
        transform: rotate(135deg) translate(-80%, 20%);
        -webkit-transform: rotate(135deg) translate(-80%, 20%);
      }
    }
  </style>

</head>

<body>
  <div class="wrapper">
    <div class="candles">
      <div class="light__wave"></div>
      <div class="candle1">
        <div class="candle1__body">
          <div class="candle1__eyes">
            <span class="candle1__eyes-one"></span>
            <span class="candle1__eyes-two"></span>
          </div>
          <div class="candle1__mouth"></div>
        </div>
        <div class="candle1__stick"></div>
      </div>

      <div class="candle2">
        <div class="candle2__body">
          <div class="candle2__eyes">
            <div class="candle2__eyes-one"></div>
            <div class="candle2__eyes-two"></div>
          </div>
        </div>
        <div class="candle2__stick"></div>
      </div>
      <div class="candle2__fire"></div>
      <div class="sparkles-one"></div>
      <div class="sparkles-two"></div>
      <div class="candle__smoke-one">

      </div>
      <div class="candle__smoke-two">

      </div>

    </div>

    <div class="floor">
    </div>

  </div>


</body>

</html>

🥵 火箭 

源码仓库在后面,文件比较多,会影响阅读,

😶‍🌫️ 时间翻盘

 原生js、vue版本,请移步仓库里

🤺 复选框动画

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>CSS3 SVG点击复选框勾选动画特效</title>

<style>
@import url("https://fonts.googleapis.com/css?family=Exo");
html {
  font-size: 100%;
}

body {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background-color: #00acc1;
  font-family: 'Exo', sans-serif;
}

input[type="checkbox"] {
  display: none;
}
input[type="checkbox"] + .label {
  position: relative;
  padding-left: 1.7em;
  color: #ffffff;
  font-size: 3.125rem;
  cursor: pointer;
}
input[type="checkbox"] + .label::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 1em;
  height: 1em;
  border: 3px solid #ffffff;
  border-radius: 0.1em;
}
input[type="checkbox"] + .label::after {
  content: '';
  position: absolute;
  top: 0.1em;
  left: 0.1em;
  width: 0.92em;
  height: 0.92em;
  transform: scale(0);
  background-color: #ffffff;
  border-radius: 0.02em;
  transition: all 0.2s linear;
  opacity: 0;
}
input[type="checkbox"] + .label svg {
  position: absolute;
  top: 0.2em;
  left: 0.12em;
  z-index: 1;
}
input[type="checkbox"] + .label #check-icon {
  stroke: #00acc1;
  stroke-dasharray: 36;
  stroke-dashoffset: 36;
}
input[type="checkbox"]:checked + .label::after {
  transform: scale(1);
  opacity: 1;
}
input[type="checkbox"]:checked + .label #check-icon {
  animation-name: check-animation;
  animation-duration: 0.2s;
  animation-delay: 0.4s;
  animation-fill-mode: forwards;
  animation-timing-function: cubic-bezier(1, 0.12, 0.96, 0.62);
}

@keyframes check-animation {
  0% {
    stroke-dashoffset: 36;
  }
  100% {
    stroke-dashoffset: 0;
  }
}
</style>

</head>
<body>

<input type="checkbox" id="check-me">

<label for="check-me" class="label">
	Check Me!
	<svg viewBox="-9 -9 43 35.191" width="43" height="35">
    	<path id="check-icon" d=" M 0 9 Q 8 17 8 17 Q 8 17 25 0" fill="none" stroke-width="6" stroke="rgb(0,0,0)" stroke-linecap="round" />
    </svg>
</label>

</body>
</html>

🤪 基础表单输入动画

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>form input动画</title>
    <style>
        input[type='text'],
        input[type='password'] {
            height: 40px;
            width: 200px;
            background: transparent;
            border: none;
            border-bottom: 1px solid #999;
            text-indent: 20px;
            transition: 0.3;
            outline: none;
        }

        input[type='text']:hover,
        input[type='password']:hover {
            border-color: #42b983;
        }

        input[type='text']:focus,
        input[type='password']:focus {
            border-bottom-color: #f1190d;
        }

        input[type='password']::-webkit-input-placeholder,
        input[type='text']::-webkit-input-placeholder {
            transition: 0.5s;
            font-size: 14px;
            transform-origin: top left;
        }

        input[type='password']:focus::-webkit-input-placeholder,
        input[type='text']:focus::-webkit-input-placeholder {
            transform: scale(0.8) translateY(-10px);
        }
    </style>
</head>

<body>
    <input type="text" placeholder="请输入您的姓名" />
    <input type="password" placeholder="请输入您的密码" />
</body>

</html>

😃 卡包动画

<template>
	<div>
		<div class="tariffCards">
			<div class="economy">
				<img
					src="https://creditcard.ecitic.com/2019_gw/images/g-logo.png"
					alt="中信银行"
					height="74"
				/>
				<h3>中信银行</h3>
				<span>zhongxin bank</span>
			</div>
			<div class="premiumeconomy">
				<img
					src="https://www.bankofchina.com/images/boc2013_logo.png"
					alt="中国银行"
					height="30"
				/>
				<h3>中国银行</h3>
				<span>chinease bank</span>
			</div>
			<div class="business">
				<img
					src="http://www.jsbchina.cn/data/tosend/resource/upload/20201127/f97a668d-3cce-435c-8cb5-ca4e69b86aec.jpg"
					alt="交通银行"
					height="74"
				/>
				<h3>交通银行</h3>
				<span>jiaotong bank</span>
			</div>
			<div class="first">
				<img
					src="http://www.jsbchina.cn/CN/index.html"
					alt="江苏银行"
					height="74"
				/>
				<h3>江苏银行</h3>
				<span>jiangsu bank</span>
			</div>
		</div>
	</div>
</template>

<style scoped>
.tariffCards {
	position: absolute;
	top: 50%;
	left: 50%;
	margin: -180px 0 0 -140px;
	user-select: none;
	transform: translate3d(0, 0, 0);
	transform-style: preserve-3d;
}
.tariffCards:after {
	position: absolute;
	bottom: -27px;
	left: 5%;
	content: '';
	width: 65%;
	height: 10px;
	border-radius: 100%;
	background-image: radial-gradient(
		rgba(34, 50, 84, 0.04),
		rgba(34, 50, 84, 0)
	);
}
.tariffCards > div {
	position: relative;
	width: 280px;
	height: 140px;
	border-radius: 12px;
	color: white;
	transform: rotateX(45deg) rotateY(-15deg) rotate(45deg);
	transition: all 0.4s ease;
	overflow: hidden;
	cursor: pointer;
}
.tariffCards > div:after {
	position: absolute;
	top: -70px;
	left: 0;
	content: '';
	width: 200%;
	height: 200%;
	background-image: linear-gradient(
		60deg,
		rgba(255, 255, 255, 0) 20%,
		rgba(255, 255, 255, 0.1),
		rgba(255, 255, 255, 0) 80%
	);
	transform: translateX(-100%);
}
.tariffCards > div img {
	margin-top: 15px;
	pointer-events: none;
}
.tariffCards > div h3 {
	position: absolute;
	bottom: 28px;
	left: 15px;
	font-size: 18px;
	font-weight: 800;
}
.tariffCards > div span {
	position: absolute;
	font-weight: 700;
	bottom: 15px;
	left: 15px;
	font-size: 12px;
	font-weight: 600;
	opacity: 0.8;
}
.tariffCards > div.economy {
	margin-top: 0;
	z-index: 3;
	background-color: #8063e1;
	background-image: linear-gradient(135deg, #bd7be8, #8063e1);
	box-shadow: 20px 20px 60px rgba(34, 50, 84, 0.5), 1px 1px 0px 1px #8063e1;
}
.tariffCards > div.premiumeconomy {
	margin-top: -70px;
	z-index: 2;
	background-color: #3f58e3;
	background-image: linear-gradient(135deg, #7f94fc, #3f58e3);
	box-shadow: 20px 20px 60px rgba(34, 50, 84, 0.5), 1px 1px 0px 1px #3f58e3;
}
.tariffCards > div.business {
	margin-top: -70px;
	z-index: 1;
	background-color: #2c6fd1;
	background-image: linear-gradient(135deg, #21bbfe, #2c6fd1);
	box-shadow: 20px 20px 60px rgba(34, 50, 84, 0.5), 1px 1px 0px 1px #2c6fd1;
}
.tariffCards > div.first {
	margin-top: -70px;
	background-color: #352f64;
	background-image: linear-gradient(135deg, #415197, #352f64);
	box-shadow: 5px 5px 60px rgba(34, 50, 84, 0.1), 1px 1px 0px 1px #352f64;
}
.tariffCards > div:hover {
	transform: rotateX(30deg) rotateY(-15deg) rotate(30deg) translate(-25px, 50px);
}
.tariffCards > div:hover:after {
	transform: translateX(100%);
	transition: all 1.2s ease-in-out;
}
</style>

😷 流光扫过动画

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .flash-container {
            width: 148px;
            height: 148px;
            background: #333333;
            margin: 0 auto;
            position: relative;
            overflow: hidden;

            &::after {
                content: '';
                height: 150%;
                width: 25px;
                background: #fff;
                position: absolute;
                left: 0;
                right: 0;
                top: 0;
                bottom: 0;
                margin: auto;
                opacity: 0.6;
                filter: blur(6px);
                animation: move 2s infinite ease-out;
            }
        }

        @keyframes move {
            0% {
                transform: translate(-200px, -200px) rotate(45deg);
            }

            100% {
                transform: translate(200px, 200px) rotate(45deg);
            }
        }
    </style>
</head>

<body>
    <div class="flash-container">
        <img src="https://img-blog.csdnimg.cn/180fbfb5f0434211b3e8640891ecea33.gif" alt />
    </div>
</body>

</html>

🥶 酷炫标题

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .wrap {
            position: relative;
            display: inline-block;
            left: 50%;
            top: 20px;
        }

        .wrap span {
            position: relative;
            z-index: 2;
            display: inline-block;
            padding: 0 15px;
            height: 32px;
            line-height: 32px;
            background-color: #42b983;
            color: #fff;
            font-size: 16px;
            box-shadow: 0 10px 6px -9px rgba(0, 0, 0, 0.6);
        }

        .wrap span::before,
        .wrap span::after {
            position: absolute;
            bottom: -6px;
            border-width: 3px 5px;
            border-style: solid;
            content: '';
        }

        .wrap span::before {
            left: 0;
            border-color: #42b983 #42b983 transparent transparent;
        }

        .wrap span::after {
            right: 0;
            border-color: #42b983 transparent transparent #42b983;
        }

        .wrap::before,
        .wrap::after {
            position: absolute;
            top: 6px;
            content: '';
            border-style: solid;
            border-color: #42b983;
        }

        .wrap::before {
            left: -32px;
            border-width: 16px 26px 16px 16px;
            border-left-color: transparent;
        }

        .wrap::after {
            right: -32px;
            border-width: 16px 16px 16px 26px;
            border-right-color: transparent;
        }
    </style>
</head>

<body>
    <div class="wrap">
        <span>距离高考还有10天</span>
    </div>
</body>

</html>

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            padding: 20px;
        }

        .wrap {
            position: relative;
            background-color: pink;
            height: 200px;
            /* width: 500px;
            margin: 0 auto; */
        }

        .left {
            width: 200px;
            height: 140px;
            position: absolute;
            top: -8px;
            left: -8px;
            overflow: hidden;
        }

        .left::before {
            position: absolute;
            left: 124px;
            border-radius: 8px 8px 0 0;
            width: 16px;
            height: 8px;
            background-color: #42b983;
            content: '';
        }

        .left::after {
            position: absolute;
            left: 0;
            top: 124px;
            border-radius: 0 8px 8px 0;
            width: 8px;
            height: 16px;
            background-color: #42b983;
            content: '';
        }

        .left span {
            display: inline-block;
            text-align: center;
            width: 200px;
            height: 40px;
            line-height: 40px;
            position: absolute;
            top: 30px;
            left: -50px;
            z-index: 2;
            overflow: hidden;
            -ms-transform: rotate(-45deg);
            -moz-transform: rotate(-45deg);
            -webkit-transform: rotate(-45deg);
            -o-transform: rotate(-45deg);
            transform: rotate(-45deg);
            border: 1px dashed #fff;
            box-shadow: 0 0 0 3px #42b983, 0 14px 7px -9px rgba(0, 0, 0, 0.6);
            background-color: #42b983;
            color: #fff;
        }

        .right {
            width: 140px;
            height: 200px;
            position: absolute;
            top: -8px;
            right: -8px;
            overflow: hidden;
        }

        .right::before {
            position: absolute;
            right: 124px;
            border-radius: 8px 8px 0 0;
            width: 16px;
            height: 8px;
            background-color: #42b983;
            content: '';
        }

        .right::after {
            position: absolute;
            right: 0;
            top: 124px;
            border-radius: 0 8px 8px 0;
            width: 8px;
            height: 16px;
            background-color: #42b983;
            content: '';
        }

        .right span {
            display: inline-block;
            text-align: center;
            width: 200px;
            height: 40px;
            line-height: 40px;
            position: absolute;
            top: 30px;
            right: -50px;
            z-index: 2;
            overflow: hidden;
            -ms-transform: rotate(45deg);
            -moz-transform: rotate(45deg);
            -webkit-transform: rotate(45deg);
            -o-transform: rotate(45deg);
            transform: rotate(45deg);
            border: 1px dashed #fff;
            box-shadow: 0 0 0 3px #42b983, 0 14px 7px -9px rgba(0, 0, 0, 0.6);
            background-color: #42b983;
            color: #fff;
        }
    </style>
</head>

<body>
    <div class="wrap">
        <div class="left">
            <span>张</span>
        </div>
        <div class="right">
            <span>坤</span>
        </div>
    </div>


</body>

</html>

🤖 交互式评分

 文件较多、参考仓库

🐔 动态向上箭头

 🐽 卸载对话框表情交互动画

 ✈️ 随机密码生成器代码

 下面是功能篇章

🧨 跟随设备切换主题

index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>切换主题 dark、light、system</title>


    <style>
        /* dark 主题  */
        [data-theme="dark"] {
            --text-color: white;
            --background-color: black;
        }

        /* light 主题  */
        [data-theme="light"] {
            --text-color: black;
            --background-color: white;
        }

        body {
            color: var(--text-color);
            background-color: var(--background-color);
        }
    </style>
</head>

<body>
    <h1>跟随设备切换主题</h1>
    <p>这是一段测试文本。</p>
    <img src="https://www4.bing.com//th?id=OHR.GoliathHeron_ZH-CN2413747227_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp&w=360&h=202"
        alt="">
    <!-- 下拉框 -->
    <select id="select-wrap" title="切换主题">
        <option value="light">light</option>
        <option value="dark">dark</option>
        <option value="system">system</option>
    </select>

    <script>
        const selectWrap = document.querySelector('#select-wrap');
        const bodyTheme = document.querySelector('body');

        window.onload = () => {
            // 获取用户的选择
            const theme = localStorage.getItem('theme');
            // 如果用户选择了主题,就设置主题同时改变下拉框的选中项
            if (theme) {
                // 设置下拉框的选中项
                selectWrap.value = theme;
                // 动态设置 system 主题
                setTheme()
            }
        }

        // 监听下拉框的变化
        selectWrap.onchange = () => {
            setTheme()
            localStorage.setItem('theme', selectWrap.value);
        }

        // 动态设置 system 主题 函数
        function setTheme() {
            /* 
            下拉框改变时,先移除 system 主题,因为dark、light主题不需要使用系统主题,
            系统主题只需要在下拉框选择 system 时才需要使用,动态添加,解决系统切换主题时,项目不需要刷新
            */
            removeSystemLink()
            if (selectWrap.value === 'system') {
                setTimeout(() => {
                    const link = document.createElement('link');
                    link.rel = 'stylesheet';
                    link.href = './system.css';
                    // 加上名称方便找到移除
                    link.id = 'system';
                    // 在head中插入link 添加到最后
                    document.head.appendChild(link);
                }, 0);
                // 在某个元素前面插入一个元素 语法:parentElement.insertBefore(newElement, targetElement)
                // parentElement是要插入新元素的父元素,newElement是要插入的新元素对象,targetElement是当前元素的前一个兄弟元素,也就是新元素要插入到这个元素之前。
                // 例子:在head中插入link 添加到最前面
                //       document.head.insertBefore(link, document.head.firstChild); 
                //       document.head.insertBefore(link, document.head.children[0]);  

                // 或者:document.head.insertBefore(link, document.head.lastChild); // 在head中插入link 添加到最后面
                // 或者:document.head.insertBefore(link, document.querySelector('title')); // 在head中插入link 添加到title前面
            } else {
                // 动态设置 light 和 dark 主题
                bodyTheme.setAttribute('data-theme', selectWrap.value);
            }
        }

        /* 
        移除 system 主题 函数:
        有时候切换系统主题了,项目还要刷新一下:
        因为系统主题的切换需要重新加载样式表才能生效,但有时候页面中的部分元素已经渲染出来,
        样式表被加载后并不会自动刷新渲染结果。在这种情况下,动态移除和添加样式表就能解决这个问题。
        */
        function removeSystemLink() {
            const link = document.querySelector('#system');
            if (link) link.remove();
        }
    </script>
</body>

</html>

 system.css

:root {
  --text-color: black;
  --background-color: white;
}

@media (prefers-color-scheme: dark) {
  :root {
    --text-color: white;
    --background-color: black;
  }
}

body {
  color: var(--text-color);
  background-color: var(--background-color);
}

🚒 昼夜切换主题

 ❤️‍🩹 使用系统取色器

<!DOCTYPE html>
<html>
<head>
  <title>使用系统取色器</title>
  <style>
    .box {
      width: 200px;
      height: 200px;
      border: 1px solid black;
    }
  </style>
</head>
<body>
  <button>打开取色器</button>
  <div class="box"></div>
  <br>
  <label></label>

  <script>
    const btn = document.querySelector('button');
    const box = document.querySelector('.box');
    const label = document.querySelector('label');

    btn.onclick = async () => {
      const dropper = new EyeDropper();

      try {
        const result = await dropper.open();
        console.log(result);
        box.style.backgroundColor = result.sRGBHex;
        label.textContent = result.sRGBHex;
      } catch {
        console.log('用户取消了操作');
      }
    }
  </script>
</body>
</html>

😃 右键动态菜单(已做边缘动画及边界外判断)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>右键菜单</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        #context-menu {
            position: fixed;
            width: 300px;
            height: 400px;
            background-image: linear-gradient(235deg, #f7f0ac, #acf7f0, #f0acf7);
            transition: all 0.3s ease-in-out;
            border-radius: 5px;
            /* 使用  display: none; 会造成边界判断失败 */
            visibility: hidden;
            opacity: 0;
            z-index: 9999;

        }

        .menu-item {
            padding: 10px;
            cursor: pointer;
        }

        .menu-item:hover {
            background-color: #d6d6d6;
        }

        .rebound {
            animation: rebound .5s;
        }

        @keyframes rebound {
            0% {
                transform: translate(-100%, 0);
                opacity: 0;
            }

            40% {
                transform: translate(10%, 0);
            }

            70% {
                transform: translate(-5%, 0);
            }

            100% {
                transform: translate(0);
                opacity: 1;
            }
        }
    </style>
</head>

<body>


    <div id="context-menu">
        <div class="menu-item">菜单项1</div>
        <div class="menu-item">菜单项2</div>
        <div class="menu-item">菜单项3</div>
    </div>

    <script>
        const contextMenu = document.getElementById('context-menu');

        function setPosition(event, menu) {
            // 获取窗口宽度和高度
            const screenWidth = window.innerWidth;
            const screenHeight = window.innerHeight;
            // 获取菜单宽度和高度
            const menuWidth = menu.offsetWidth;
            const menuHeight = menu.offsetHeight;
            // 获取鼠标在页面中的位置
            const x = event.clientX;
            const y = event.clientY;
            // 计算菜单的调整后的水平位置和垂直位置
            const adjustedX = (x + menuWidth) >= screenWidth ? (x - menuWidth) : x; // 检查是否超出右侧边界
            const adjustedY = (y + menuHeight) >= screenHeight ? (y - menuHeight) : y; // 检查是否超出底部边界
            // 如果超出右侧边界,让菜单反弹一下
            if (adjustedX !== x) {
                menu.classList.add('rebound');
                setTimeout(() => {
                    menu.classList.remove('rebound');
                }, 1000);
            }
            // 设置菜单的位置
            menu.style.left = adjustedX + 'px';
            menu.style.top = adjustedY + 'px';
        }

        document.addEventListener('contextmenu', function (event) {
            event.preventDefault(); // 阻止系统默认的右键菜单
            setPosition(event, contextMenu); // 计算并设置菜单的位置
            contextMenu.style.visibility = 'visible'; // 显示菜单
            contextMenu.style.opacity = '1';
        });

        // 如果点击的地方不在菜单内,隐藏菜单
        document.addEventListener('click', function (event) {
            console.log(event.target);
            console.log(contextMenu);
            if (contextMenu !== event.target) {
                contextMenu.style.visibility = 'hidden';
                contextMenu.style.opacity = '0';
            }
        });


        const menuItems = document.querySelectorAll('.menu-item');
        // 为每个菜单项添加事件监听 不优化
        // for (let i = 0; i < menuItems.length; i++) {
        //     menuItems[i].addEventListener('click', function (event) {
        //         console.log(`您点击了菜单项${i + 1}`);
        //                     contextMenu.style.visibility = 'visible';

        //     });
        //     menuItems[i].addEventListener('mousedown', function (event) {
        //         event.stopPropagation();
        //     });
        // }

        // 使用事件委托 优化
        contextMenu.addEventListener('click', function (event) {
            const target = event.target;
            if (target.classList.contains('menu-item')) {
                // indexOf() 返回指定元素在目标队列中首次出现的索引,找不到指定元素,则会返回 -1。
                // call 第一个参数是指定该方法执行时的上下文环境(写谁指向谁),第二个参数,它表示要传递给被调用的方法的参数。
                const index = Array.prototype.indexOf.call(menuItems, target);
                console.log(`您点击了菜单项${index + 1}`);
            }
        });
    </script>

</body>

</html>

🎋 酷炫打字特效

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>删库跑路</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        border: 0;
        font-size: 100%;
        font: inherit;
        vertical-align: baseline;
        box-sizing: border-box;
        color: inherit;
      }

      body {
        background-image: linear-gradient(120deg, #4f0088 0%, #000 100%);
        height: 100vh;
      }

      div {
        background: rgba(0, 0, 0, 0);
        width: 70vw;
        position: relative;
        top: 50%;
        -webkit-transform: translateY(-50%);
        transform: translateY(-50%);
        margin: 0 auto;
        padding: 30px 30px 10px;
        box-shadow: 0 0 150px -20px rgba(0, 0, 0, 0.5);
        z-index: 3;
      }

      P {
        font-family: "Share Tech Mono", monospace;
        color: #f5f5f5;
        margin: 0 0 20px;
        font-size: 17px;
        line-height: 1.2;
      }

      span {
        color: #f0c674;
      }

      i {
        color: #8abeb7;
      }

      div a {
        text-decoration: none;
      }

      b {
        color: #81a2be;
      }

      a.avatar {
        position: fixed;
        bottom: 15px;
        right: -100px;
        -webkit-animation: slide 0.5s 4.5s forwards;
        animation: slide 0.5s 4.5s forwards;
        display: block;
        z-index: 4;
      }

      a.avatar img {
        border-radius: 100%;
        width: 44px;
        border: 2px solid white;
      }

      @-webkit-keyframes slide {
        from {
          right: -100px;
          -webkit-transform: rotate(360deg);
          transform: rotate(360deg);
          opacity: 0;
        }

        to {
          right: 15px;
          -webkit-transform: rotate(0deg);
          transform: rotate(0deg);
          opacity: 1;
        }
      }

      @keyframes slide {
        from {
          right: -100px;
          -webkit-transform: rotate(360deg);
          transform: rotate(360deg);
          opacity: 0;
        }

        to {
          right: 15px;
          -webkit-transform: rotate(0deg);
          transform: rotate(0deg);
          opacity: 1;
        }
      }
    </style>
  </head>

  <body>
    <div id="container">
      <p>
        >
        <span> [root@VM-0-7-centos ~]# </span>
        : "
        <i> rm -rf /*正在删除本地的数据 </i>
        "
      </p>

      <p>
        >
        <span> [root@VM-0-7-centos ~]# </span>
        : "
        <i> 删除成功 </i>
        "
      </p>

      <p>
        >
        <span> [root@VM-0-7-centos ~]# </span>
        : "
        <i> 文件备份自动启用中... </i>
        "
      </p>

      <p>
        >
        <span> [root@VM-0-7-centos ~]# </span>
        : "
        <i> 备份失败! 仅备份文件碎片... </i>
        "
      </p>

      <p>
        >
        <span> [root@VM-0-7-centos ~]# </span>
        : "
        <i> 文件碎片正在加载... </i>
        "
      </p>

      <p>
        >
        <span> [root@VM-0-7-centos ~]# </span>
        : "
        <i> 加载失败 对不起我们跑路了... </i>
        "
      </p>

      <p>
        >
        <span> [root@VM-0-7-centos ~]# </span>
        : "
        <i> 不要伤心 不要难过... </i>
        "
      </p>

      <p>
        >
        <span> [root@VM-0-7-centos ~]# </span>
        : "
        <i> 或许我们还会再建个站继续骗你 ... </i>
        "
      </p>

    </div>

    <script>
      // 将元素内容转换为字符串
      let str = document.querySelector("#container").innerHTML.toString();
      let i = 0;
      let containerHtml = document.querySelector("#container");
      containerHtml.innerHTML = "";
      setTimeout(function () {
        let se = setInterval(function () {
          i++;
        //   str.slice(start, end) 表示从 str 字符串的 start 索引处开始,提取到 end 索引处之前(不包含 end)的子串。如果不指定 end 参数,则默认提取到字符串末尾。
          containerHtml.innerHTML = str.slice(0, i) + "|";
          if (i == str.length) {
            clearInterval(se);
            containerHtml.innerHTML = str;
          }
        }, 30);
      }, 0);
    </script>
  </body>
</html>

🚆 方形抽奖

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>转盘</title>
    <style>
      .main {
        display: flex;
        width: 320px;
        flex-wrap: wrap;
      }
      .item {
        width: 100px;
        height: 100px;
        background-color: #ddd;
        display: flex;
        align-items: center;
        justify-content: center;
        border: 2px solid #fff;
      }
      .item.active {
        background-color: #999;
      }
      .item.btn {
        background-color: green;
        color: #fff;
      }
    </style>
  </head>
  <body>
    <div class="main"></div>

    <script>
      window.onload = () => {
        const data = {
          jp: [
            { name: "代金券1" },
            { name: "代金券2", is: true },
            { name: "代金券3" },
            { name: "代金券4" },
            { name: "代金券5" },
            { name: "代金券6" },
            { name: "代金券7" },
            { name: "代金券8" },
          ],
        };

        const main = document.querySelector(".main");
        main.innerHTML = data.jp
          .map(
            (v) =>
              `<div class="item" ${v.is ? "is='true'" : ""}>${v.name}</div>`
          )
          .join("");

        const btnEl = document.createElement("div");
        btnEl.className = "item btn";
        btnEl.innerHTML = "抽奖";

        main.insertBefore(btnEl, main.children[4]);

        let isRunning = false;
        let itemIndex = 0;

        const spinWheel = () => {
          const nodesList = [...main.childNodes].filter(
            (v) => !v.classList.contains("btn")
          );
          const spinOrder = [0, 1, 2, 4, 7, 6, 5, 3];
          const spinItems = spinOrder.map((v) => nodesList[v]);

          if (!spinItems[itemIndex]) {
            itemIndex = 0;
          }

          const active1 = main.querySelector(".active");
          active1 && active1.classList.remove("active");

          spinItems[itemIndex].classList.add("active");

          if (!isRunning && spinItems[itemIndex].getAttribute("is")) {
            clearInterval(intervalId);
          }

          itemIndex++;
        };

        let intervalId;
        btnEl.onclick = () => {
          if (isRunning) return;

          isRunning = true;
          intervalId = setInterval(spinWheel, 100);

          setTimeout(() => {
            isRunning = false;
          }, 3000);
        };
      };
    </script>
  </body>
</html>

🚼 圆形抽奖


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>转盘</title>
<style>
    .zp {
        position: relative;
        border-radius: 100%;
        width: 300px;
        overflow: hidden;
        margin:0 auto;
    }
    .zp-panel {
        background: url(./images/zp.webp) no-repeat center center;
        background-size: 100%;
        width: 300px;
        height: 300px;
        position: relative;
        transition: transform 4s ease-out;
        
    }
    .item {
        font-size: 12px;
        position: absolute;
        top: 50%;
        left: 0;
        right: 0;
        text-align: center;
        margin-top: -7px;
        line-height: 1;
    }
    .btn {
        position: absolute;
        background-color: green;
        width: 80px;
        height: 80px;
        border-radius: 100%;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        z-index: 2;
        display: flex;
        align-items: center;
        justify-content: center;
        color: #fff;
    }
    .btn:after {
        content: '';
        position: absolute;
        height: 80px;
        width: 4px;
        background-color: green;
        left: 38px;
        bottom: 60px;
    }
</style>

</head>
<body>
    <div class="zp">
        <div class="zp-panel"></div>
        <div class="btn">开始</div>
    </div>
</body>
<script>
    const arr = [
        {name: '积分+1'},
        {name: '积分+2'},
        {name: '积分+3'},
        {name: '积分+4'},
        {name: '电动车一辆', is: true},
        {name: '积分+10'}
    ]
    const zp = document.querySelector('.zp-panel')
    const btn = document.querySelector('.btn')
    const d = 360 / arr.length
    zp.innerHTML = arr.map((v, i) => {
        return `<div class="item" 
            style="transform:rotate(${i*d - 90}deg) translate(75px)">${v.name}</div>`
    }).join('')
    btn.onclick = () => {
        const zpIndex = arr.findIndex(v => v.is)
        const deg = -(zpIndex * d + 720)
        // 清空上次抽奖,暂停动画效果
        zp.style.transition = 'inherit'
        zp.style.transform = ''
        setTimeout(() => {
            // 重置transition,恢复动画效果
            zp.style.transition = ''
            setTimeout(() => {
                // 触发动画
                zp.style.transform  = `rotate(${deg}deg)`
            })
        })
    }
</script>
</html>

🛹 吸顶楼层导航

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>楼层滚动</title>
  </head>
  <style>
    * {
      padding: 0;
      margin: 0;
    }
    body,
    html {
      height: auto;
      width: 100%;
      background-image: linear-gradient(to right, #f7f0ac, #acf7f0, #f0acf7);
    }
    .nav-wrap {
      position: fixed;
      z-index: 99;
      top: 50%;
      left: 120px;
      transform: translateY(-50%);
      width: 100px;
      height: 300px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: space-between;
    }
    .stick {
      position: sticky;
      top: 10px;
      height: 15px;
      padding: 5px;
      line-height: 15px;
      background-color: #5f9ea0;
      color: #ffff;
      font-weight: 900;
    }
    .nav {
      width: 100px;
      flex: 1;
      margin-bottom: 10px;
      background: url(https://img1.baidu.com/it/u=105002249,3897918256&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=281)
        no-repeat center center/cover;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 25px;
    }
    .main {
      text-align: center;
      line-height: 900px;
      font-size: 30px;
      color: #ffff;
      width: 800px;
      height: 900px;
      /* background-color: hsla(0, 0%, 100%, 0.2); */
      background: rgba(255, 255, 255, 0.4);
      position: relative;
      left: 50%;
      transform: translateX(-50%);
    }
    .nav-active {
      color: red;
      background: url("https://img1.baidu.com/it/u=833204098,2930185410&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=745")
        no-repeat center center/cover;
    }
  </style>

  <body>
    <div class="nav-wrap">
      <div class="nav">A</div>
      <div class="nav">B</div>
      <div class="nav">C</div>
      <div class="nav">D</div>
    </div>

    <div class="main">A</div>

    <div class="main">
      <div class="stick">B</div>
    </div>

    <div class="main">
      <div class="stick">C</div>
    </div>

    <div class="main">
      <div class="stick">D</div>
    </div>
  </body>
  <script>
    const navAll = document.querySelector(".nav-wrap");
    const mainAll = document.querySelectorAll(".main");

    function reset() {
      for (let i = 0; i < navAll.children.length; i++) {
        navAll.children[i].classList.remove("nav-active");
      }
    }
    // 进入页面时,第一个导航栏高亮
    navAll.children[0].classList.add("nav-active");

    navAll.addEventListener("click", (event) => {
      if (event.target.classList.contains("nav")) {
        const index = Array.from(navAll.children).indexOf(event.target);
        console.log(index);
        window.scrollTo({
          top: Math.floor(mainAll[index].offsetTop),
          behavior: "smooth",
        });
      }
    });

    window.addEventListener("scroll", () => {
      const scrollTop = document.scrollingElement.scrollTop;
      let left = 0;
      let right = navAll.children.length - 1;

      while (left <= right) {
        const mid = Math.floor((left + right) / 2);
        const currentMain = mainAll[mid];

        if (
          currentMain.offsetTop <= scrollTop &&
          currentMain.offsetTop + currentMain.offsetHeight > scrollTop
        ) {
          reset();
          navAll.children[mid].classList.add("nav-active");
          break;
        } else if (currentMain.offsetTop > scrollTop) {
          right = mid - 1;
        } else {
          left = mid + 1;
        }
      }
    });
  </script>
</html>

✈️ 困了盖坤

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />

  <title>羊了个羊</title>
  <style>
    * {
      box-sizing: border-box;
    }

    body {
      margin: 0;
    }

    .main {
      position: relative;
    }

    .item {
      position: absolute;
      background: no-repeat center center #ffffff;
      border: 1px solid #ddd;
      background-size: 100%;
      color: transparent;
      display: flex;
      justify-content: center;
      align-items: center;
      z-index: 0;
      transition: left 0.3s, top 0.3s, transform 0.3s;
    }

    .item:after {
      content: "";
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      transition: background-color 0.2s;
    }

    .disabled:after {
      background-color: rgba(0, 0, 0, 0.7);
    }

    .move-list {
      border: 1px solid #ddd;
      background-color: #ddd;
      margin: 0 auto;
    }
  </style>
</head>

<body>
  <div class="main"></div>
  <div class="move-list"></div>
</body>
<script>
  // 基础数据
  const simpleData = [
    { name: "虎", color: "#ff1100", bg: "./xxl-img/1.png" },
    { name: "兔", color: "#ff8800", bg: "./xxl-img/2.png" },
    { name: "牛", color: "green", bg: "./xxl-img/3.png" },
    { name: "羊", color: "blue", bg: "./xxl-img/4.png" },
    { name: "蛇", color: "#779922", bg: "./xxl-img/5.png" },
    { name: "鼠", color: "#335577", bg: "./xxl-img/6.png" },
  ];
  // 卡片大小
  const size = 40;
  // 矩阵行
  const rows = 10;
  // 矩阵列
  const cols = 10;
  // 每组为3个
  const oneGoupCount = 3;
  // 每个卡片有x组
  const group = 6;
  // 总共6层,即6个表格
  const layerCount = 6;
  // 表格html
  const cellHtml = [];
  // 将生成所有的十二生肖
  const renderData = Array.from(new Array(oneGoupCount * group))
    .map((v) => {
      return simpleData.map((v) => ({ ...v }));
    })
    .flat()
    .sort((v) => Math.random() - 0.5);
  // 第一步:绘制出表格矩阵
  for (let ly = layerCount - 1; ly >= 0; ly--) {
    for (let i = 0; i < rows; i++) {
      for (let j = 0; j < cols; j++) {
        let pyStep = (ly + 1) % 2 === 0 ? size / 2 : 0;
        let item = Math.random() > 0.7 && renderData.pop();

        item &&
          cellHtml.push(`<div class="item" onclick="move(this)" id="m${ly}-${i}-${j}"
                    style="width:${size}px;height:${size}px;left:${size * j + pyStep}px;top:${size * i + pyStep
            }px;background-image:url(${item.bg || ""})">${item.name || ""}</div>`);
      }
    }
  }
  const main = document.querySelector(".main");
  const moveList = document.querySelector(".move-list");
  main.innerHTML = cellHtml.reverse().join("");
  main.style.height = `${size * rows + size * 2}px`;
  main.style.width = `${size * cols}px`;
  moveList.style.height = `${size}px`;
  moveList.style.width = `${size * 6}px`;
  // 第二步:计算被遮住的底牌需标暗色
  const checkDisabled = (items) => {
    (items || main.querySelectorAll(".item")).forEach((v, i) => {
      const arr = v.id
        .substring(1)
        .split("-")
        .map((v) => Number(v));
      const isPy = (arr[0] + 1) % 2 === 0;
      for (let i = arr[0] + 1; i <= layerCount - 1; i++) {
        const isPyB = (i + 1) % 2 === 0;
        if (isPy === isPyB) {
          const el = main.querySelector(`#m${i}-${arr[1]}-${arr[2]}`);
          if (el) {
            v.classList.add("disabled");
            break;
          }
        } else if (isPy && !isPyB) {
          if (
            ![
              `${i}-${arr[1]}-${arr[2]}`,
              `${i}-${arr[1]}-${arr[2] + 1}`,
              `${i}-${arr[1] + 1}-${arr[2]}`,
              `${i}-${arr[1] + 1}-${arr[2] + 1}`,
            ].every((k) => {
              return !main.querySelector("#m" + k);
            })
          ) {
            v.classList.add("disabled");
            break;
          } else {
            v.classList.remove("disabled");
          }
        } else if (!isPy && isPyB) {
          if (
            ![
              `${i}-${arr[1]}-${arr[2]}`,
              `${i}-${arr[1]}-${arr[2] - 1}`,
              `${i}-${arr[1] - 1}-${arr[2]}`,
              `${i}-${arr[1] - 1}-${arr[2] - 1}`,
            ].every((k) => {
              return !main.querySelector("#m" + k);
            })
          ) {
            v.classList.add("disabled");
            break;
          } else {
            v.classList.remove("disabled");
          }
        }
      }
    });
  };
  // 第三步:点击卡片进行消除计算
  let canMove = true;
  // 点击棋子,动画移动
  const move = (me) => {
    let left = moveList.offsetLeft;
    let top = moveList.offsetTop;
    if (!canMove || me.className.indexOf("disabled") >= 0) {
      return;
    }
    canMove = false;
    if (moveList.children.length > 0) {
      let el = moveList.children[moveList.children.length - 1];
      left = el.offsetLeft + size;
      top = el.offsetTop;
    }
    me.style.top = `${top}px`;
    me.style.left = `${left}px`;
    me.transitionNamesCount = 0;
    me.ontransitionend = (e) => {
      me.transitionNamesCount++;
      if (me.transitionNamesCount === 2) {
        moveEnd(me);
        canMove = true;
      }
    };
  };
  // 动画结束的相关计算
  const moveEnd = (me) => {
    me.ontransitionend = null;
    me.setAttribute("onclick", "");
    moveList.appendChild(me);

    const findResult = [...moveList.children].filter((v) => v.innerHTML === me.innerHTML);
    if (findResult.length === 3) {
      findResult.forEach((v) => {
        v.ontransitionend = (e) => {
          moveList.removeChild(v);
          [...moveList.children].forEach((v, i) => {
            v.style.left = `${i * size + moveList.offsetLeft}px`;
          });
        };
        setTimeout(() => (v.style.transform = "scale(0)"));
      });
    }
    if (moveList.children.length === 6) {
      return alert("池子已满,游戏结束");
    } else if (main.children.length === 0) {
      return alert("恭喜通关");
    }
    checkDisabled();
  };
  checkDisabled();
</script>

</html>

🛫 扣扣乐

<canvas id="cvs" width="605" height="338"></canvas>
<style>
    canvas {
        background: url(./images/zj.png) no-repeat center center;
        background-size: 100%;
    }
</style>
<script>
    const cvs = document.getElementById('cvs')
    const ctx = cvs.getContext('2d')
    const url = './images/zj-bg.jpeg'
    const img = new Image()
    img.src = url
    img.onload = () => {
        ctx.drawImage(img, 0, 0, cvs.width, cvs.height)
    }
    let isClearing = false
    cvs.addEventListener('mousedown', e => {
        isClearing = true
    })
    cvs.addEventListener('mousemove', e => {
        if (isClearing) {
            const clearSize = 60
            ctx.clearRect(e.pageX - clearSize, e.pageY - clearSize,
                clearSize, clearSize)
        }
    })
    document.addEventListener('mouseup', e => {
        isClearing = false
    })
</script>

🍰 签名回溯

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>HTML5 绘图</title>
    <style>
      .canvas {
        border: 1px solid #ccc;
        cursor: crosshair;
      }
    </style>
  </head>
  <body>
    <input type="button" value="重放" id="btn1" />
    <input type="button" value="清空" id="btn2" />
    <input type="button" value="保存" id="btn3" />

    <br />
    <canvas id="cvs" class="canvas"></canvas>
  </body>
</html>
<script>
  class Draw {
    constructor(selector, width, height) {
      this.element = document.querySelector(selector);
      this.canvas = this.element.getContext("2d");
      this.element.width = width;
      this.element.height = height;
      this.timeId = null;
      this.animateArr = [];
    }
    init() {
      const { canvas: c, element: el } = this;
      let isDrag = false;

      c.lineWidth = 2;
      c.lineJoin = "round";
      c.shadowColor = "#000";
      c.shadowBlur = 4;

      el.onmousedown = () => {
        isDrag = true;
        c.beginPath();
      };
      el.onmousemove = (e) => {
        if (isDrag) {
          const x = e.pageX - el.offsetLeft;
          const y = e.pageY - el.offsetTop;
          c.lineTo(x, y);
          c.stroke();
          this.animateArr.push([x, y]);
        }
      };
      el.onmouseup = () => {
        isDrag = false;
        this.animateArr.push(-1);
      };
      el.onmouseout = () => {
        el.onmouseup();
      };
    }
    animateGo() {
      const { canvas: c } = this;
      this.clear();
      c.beginPath();
      const loop = (animate, i) => {
        if (i < animate.length - 1) {
          const arr = animate[i];
          if (arr === -1) {
            c.beginPath();
          } else {
            c.lineTo(arr[0], arr[1]);
            c.stroke();
          }
          i++;
          this.timeId = setTimeout(() => {
            loop(animate, i);
          }, 10);
        }
      };
      loop(this.animateArr, 0);
    }
    clear() {
      const { canvas: c } = this;
      const { width, height } = this.element;
      c.clearRect(0, 0, width, height);
    }
  }
  const g = new Draw("#cvs", 600, 500);
  g.init();
  document.getElementById("btn1").onclick = () => {
    g.animateGo();
  };
  document.getElementById("btn2").onclick = () => {
    g.clear();
    g.animateArr = [];
  };
  document.getElementById("btn3").onclick = () => {
    const canvas = document.querySelector("#cvs");
    const dataURL = canvas.toDataURL();
    // 将dataURL发送到服务器进行保存操作
    console.log(dataURL);
  };
</script>

🌍 翻盘抽奖

 画面 挺多、不一一展示了,快来一键三连抱走吧

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>9宫格翻牌抽奖</title>
    <style>
        .title {
            text-align: center;
        }
        .box {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            width: 330px;
            margin:0 auto;
        }
        .item {
            position: relative;
            margin: 5px;
            width: 100px;
            height: 100px;
        }
        .style1, .style2 {
            position: absolute;
            left:0;
            top: 0;
            bottom: 0;
            right: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            border-radius: 5px;
            text-align: center;
            transition: transform .4s
        }
        .style1 {
            background-color: #ff8800;
            color: #fff;
        }
        .style2 {
            color: #ff8800;
            border:1px solid #ff8800;
            padding: 0 10px;
            transform: scaleX(0);
            background-color: #ffe6c9;
        }
        .hide {
            transform: scaleX(0);
        }
        .show {
            transform: scaleX(1);
        }
        .show-result {
            transform: scaleX(1);
            opacity: 0.5;
        }
    </style>
</head>
<style>
</style>
<body>
    <div class="title">可抽奖<label id="count">0</label>次</div>
    <div class="box"></div>
</body>
<script>
    // 奖品列表
    const list = [
        {id: 1, name: '1元优惠券', is: true},
        {id: 2, name: '10元优惠券', is: true},
        {id: 3, name: '谢谢惠顾', is: true},
        {id: 4, name: '豪华电动车'},
        {id: 5, name: '1w购物券'},
        {id: 6, name: '5w购物券'},
        {id: 7, name: '豪华轿车'},
        {id: 8, name: '房子一套'},
        {id: 9, name: '顶配笔记本'}
    ].sort(v => Math.random() - 0.5)
    // 中奖项
    const isArr = list.filter(v => v.is)
    // 非中奖项
    const noArr = list.filter(v => !v.is)
    // 抽奖次数
    let count = 3
    const box = document.querySelector('.box')
    const countEL = document.querySelector('#count')
    countEL.innerHTML = count
    box.innerHTML = list.map(v => {
        return `<div class="item" onclick="fp(this)">
            <div class="style1">抽奖</div>
            <div class="style2"></div>
        </div>`
    }).join('')
    // 翻牌抽奖
    const fp = (me) => {
        if (count === 0) {
            return
        }
        me.querySelector('.style1').classList.add('hide')
        // 抽奖动画
        setTimeout(() => {
            // 从非中奖项中取最后一个,并从数组中移除该项
            const item = isArr.pop()
            const style2 = me.querySelector('.style2')
            style2.innerHTML = item.name
            style2.classList.add('show')
        }, 400)
        count--
        countEL.innerHTML = count
        // 当抽奖次数为0的时候,就把剩余的奖项全部展示出来
        if (count === 0) {
            setTimeout(() => {
                box.querySelectorAll('.style1').forEach(v => {
                    v.classList.add('hide')
                    if (v.nextElementSibling.className.indexOf('show') === -1) {
                        const item = noArr.pop()
                        v.nextElementSibling.innerHTML = item.name
                    }
                })
                setTimeout(() => {
                    box.querySelectorAll('.style2').forEach(v => {
                        if (v.className.indexOf('show') === -1) {
                            v.classList.add('show-result')
                        }
                    })
                }, 400)
            }, 1000)
        }
    }
</script>
</html>

🪂 地址 🤺🤺🤺 

  

 🥰😉  谢谢观看

7730e2bd39d64179909767e1967da702.jpeg

 _______________________________  期待再见  _______________________________ 

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

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

相关文章

window电脑修复网络不能正常

问题描述 问题的起点是我打开了OpenAPI公司的GPT&#xff0c;在回答的过程中响应很慢&#xff0c;然后自己开始尝试切换连接的服务器&#xff08;这里使用到了网络代理&#xff09;&#xff0c;最后自己做了一个操作是 代理软件的这个菜单里面的增强模式选项&#xff0c;结果…

Android爬坑指南————工信部又出新规!

工信部又出新规了&#xff01; 一、背景二、整改2.1 个人信息保护2.1.1 基本模式&#xff08;无权限、无个人信息获取模式&#xff09;腾讯视频网易云音乐 2.1.2 隐私政策内容 2.2 app权限调用2.2.1 应用内权限调用2.2.1.1 获取定位信息和生物特征识别信息2.2.1.2 其他权限 2.3…

渲染流程(上):HTML、CSS和JavaScript,是如何变成页面的?

在上一篇文章中我们介绍了导航相关的流程&#xff0c;那导航被提交后又会怎么样呢&#xff1f; 就进入了渲染阶段。这个阶段很重要&#xff0c;了解其相关流程能让你“看透”页面是如何工作的&#xff0c;有了这些知识&#xff0c;你可以解决一系列相关的问题&#xff0c;比如…

SVR算法简介及与其它回归算法的关系

目录 参考链接 有人可以帮助我理解支持向量回归技术和其他简单回归模型之间的主要区别是什么 支持向量回归找到一个线性函数&#xff0c;表示误差范围 (epsilon) 内的数据。也就是说&#xff0c;大多数点都可以在该边距内找到&#xff0c;如下图所示 这意味着 SVR 比大多数其…

TypeScript 学习笔记(一):基本类型、交叉类型、联合类型、类型断言

文章目录 一、常见类型1. 数组2. 布尔3. 数值4. 字符串5. object6. null 和 undefined7. symbol7.1 作为属性名7.2 属性名遍历7.3 静态方法&#xff1a;Symbol.for()和 Symbol.keyFor()7.4 内置 symbol 值7.4.1 Symbol.hasInstance7.4.2 Symbol.isConcatSpreadable7.4.3 Symbol…

Android 报错,闪退(错误)日志保存到手机内存中,以文本文件的形式保存

1.直接贴代码 import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Environment; import android.util.Log;import com.nuotu.atmBookClient.App;import java.io.File; i…

python接口自动化(三十二)--Python发送邮件(常见四种邮件内容)番外篇——上(详解)

简介 本篇文章与前边没有多大关联&#xff0c;就是对前边有关发邮件的总结和梳理。在写脚本时&#xff0c;放到后台运行&#xff0c;想知道执行情况&#xff0c;会通过邮件、SMS&#xff08;短信&#xff09;、飞信、微信等方式通知管理员&#xff0c;用的最多的是邮件。在linu…

这份4577页的Java面试PDF,让我成功斩获阿里、字节等大厂offer

我为大家准备了一份超级全面的Java 学习面试笔记&#xff0c;这份电子版笔记涵盖了诸多后端技术栈的面试题和答案&#xff0c;相信可以帮助大家在最短的时间内复习Java后端的大多数技术点和面试题&#xff0c;从而拿到自己心仪的offer。共4577页。整体还是比较清爽的&#xff0…

Postman的细节回顾

之前在学校摸索着玩过postman&#xff0c;工作后要使用postman&#xff0c;发现对于很多细节&#xff0c;这里补充说明一下&#xff0c;当作使用手册。 之所以使用postman&#xff0c;是因为更便捷的查看接口情况&#xff0c;不需要每次在浏览器f12查看。 目录 1 创建请求2 测…

产品经理怎么管理项目进度?

作为在职七年的项目管理人员&#xff0c;在项目进度管理上确实有一点发言权。产品经理作为企业的核心骨干岗位之一&#xff0c;在进行项目进度管理时也会有很多问题出现&#xff0c;那么应该怎样去管理项目进度呢&#xff1f;以下是答主的一些拙见&#xff0c;有需要的朋友们就…

C. Particles

Problem - C - Codeforces 思路&#xff1a;通过题意能够知道如果移除i&#xff0c;那么i-1与i1会合成一个新的&#xff0c;同时后面的往前移动两个单位&#xff0c;并且我们发现可以让1 3 5 7 ... 2*n-1合成一个数&#xff0c;让2 4 6 8 ... 2*n合成一个数&#xff0c;同时我们…

java自我学习记录day02

java日常学习 1.继承2.super3.方法重写/覆盖4.多态5.Object类和equals的对比equals用于判断值是否相等hashCode方法toString方法finalize方法 6.刷题&#xff08;03&#xff09;题三&#xff1a;在排序数组中查找元素的第一个和最后一个位置 1.继承 如果希望指定去调用父类的某…

uniapp 小程序 filters 过滤日期

页面效果&#xff1a; <template><view class"order-intro-item"><text class"left-label">日期</text><text class"right-info time-text">{{startClearingTime | formatData}} 至 {{endClearingTime | format…

21. 斐波那契数列

链接&#xff1a; 链接 题目&#xff1a; 输入一个整数 nn &#xff0c;求斐波那契数列的第 nn 项。 假定从 00 开始&#xff0c;第 00 项为 00。 数据范围 0≤n≤390≤n≤39 样例 输入整数 n5 返回 5 思路&#xff1a; 0返回0&#xff0c;1&#xff0c;2都返回1&#xff0c;后…

数据库备份恢复和索引视图

样例表如下&#xff1a; /***************************样例表***************************/CREATE DATABASE booksDB;use booksDB;CREATE TABLE books(bk_id INT NOT NULL PRIMARY KEY,bk_title VARCHAR(50) NOT NULL,copyright YEAR NOT NULL);INSERT INTO booksVALUES (1107…

IPv6 over IPv4 之SIT隧道

一.SIT模块功能简介 SIT模块是支持ISATAP隧道和6to4隧道两种隧道模式的 ISATAP和6to4都是目前比较流行的自动建立隧道的过渡技术&#xff0c;都可以连接被IPv4隔绝的IPv6孤岛&#xff0c;都是通过将IPv4地址嵌入到IPv6地址当中&#xff0c;并将IPv6封包封装在IPv4中传送&…

第一章介绍处理器(Cortex-M7 Processor)

目录 第一章引言本章介绍处理器。 1.1关于Cortex-M7处理器 1.1.1特性 1.1.2接口 1.1.3配置选项 1.2组件模块 1.2.1数据处理单元 1.2.2预取单元 1.2.3负载存储单元 1.2.4浮点单元 1.2.5嵌套矢量中断控制器 1.2.6唤醒中断控制器 1.2.7记忆系统 1.2.8存储缓冲区 1.2.9内…

从数据中看天气变迁:Python获取历史天气数据

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 需要知识点 : 动态数据抓包 requests发送请求 结构化非结构化数据解析 开发环境 : python 3.8 运行代码 pycharm 2022.3.2 辅助敲代码 专业版 requests 发送请求 pip install requests parsel 解析数据 pip inst…

cuda中radix_sort

背景 radix_sort排序是一种经典排序&#xff0c;在gpu上都有对其进行支持&#xff0c;这里主要参考cub中的实现&#xff0c;简单介绍一种单block的情形, 本文只适合看过源码但是没有看懂的同学。 流程 在second step中完全实在ScanCounters()函数中&#xff0c;具体分为upswe…

怎样将视频中的音频提取出来? 分享三个方法!

在处理视频时&#xff0c;有时我们需要将视频中的音频提取出来&#xff0c;可能是为了编辑或处理音频&#xff0c;或者仅仅是想保存音频本身。无论是出于什么目的&#xff0c;以下是三种简单的方法来提取视频中的音频&#xff1a; 方法一&#xff1a;修改文件后缀 这是一种简…