HTML&CSS:雪花飘落邮票动画

93 阅读4分钟

这段代码创建了一个带有动画效果的邮票场景,通过 CSS 和 JavaScript 技术模拟了雪花的下落和邮票的装饰效果,为页面添加了节日气氛。

演示效果

HTML&CSS

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>公众号关注:前端Hardy</title>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400..700&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');

        :root {
            --bg: #fffaed;
            --blue: #90c2d1;
            --red: #d14a45;
            --white: #fffaed;
            --brown: #363334;
        }

        body {
            height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            background: var(--bg);
        }

        div.stamp {
            position: relative;
            display: flex;
            align-items: center;
            justify-content: center;
            height: 200px;
            width: 345px;
            background: var(--blue);
        }

        div.stamp::before {
            content: "";
            bottom: 0;
            position: absolute;
        }

        div.stamp::after {
            content: "";
            position: absolute;
            top: 0;
            left: 0;
            height: 20px;
            width: 20px;
            border-radius: 50%;
            background: var(--blue);
            transform: translateY(-12px) translateX(12px);
            box-shadow: 30px 0px var(--blue), 60px 0px var(--blue), 90px 0px var(--blue), 120px 0px var(--blue), 150px 0px var(--blue), 180px 0px var(--blue), 210px 0px var(--blue), 240px 0px var(--blue), 270px 0px var(--blue), 300px 0px var(--blue), 0px 205px var(--blue), 30px 205px var(--blue), 60px 205px var(--blue), 90px 205px var(--blue), 120px 205px var(--blue), 150px 205px var(--blue), 180px 205px var(--blue), 210px 205px var(--blue), 240px 205px var(--blue), 270px 205px var(--blue), 300px 205px var(--blue), -23px 25px var(--blue), -23px 55px var(--blue), -23px 85px var(--blue), -23px 115px var(--blue), -23px 145px var(--blue), -23px 175px var(--blue), 324px 25px var(--blue), 324px 55px var(--blue), 324px 85px var(--blue), 324px 115px var(--blue), 324px 145px var(--blue), 324px 175px var(--blue);
        }

        div.inner-stamp {
            display: flex;
            align-items: flex-end;
            position: relative;
            overflow: hidden;
            background-image: linear-gradient(#27272a, #304259);
            height: 165px;
            width: 310px;
        }

        div.inner-stamp::before {
            content: "来自Hardy的祝福";
            color: var(--white);
            display: flex;
            align-items: center;
            justify-content: center;
            position: absolute;
            font-weight: 400;
            font-family: Inter;
            font-size: 12px;
            width: 310px;
            height: 26px;
            background: var(--red);
            letter-spacing: 3px;
            z-index: 100;
        }

        .house {
            display: flex;
            justify-content: center;
            margin-left: 19px;
            height: 30px;
            margin-bottom: 10px;
            width: 40px;
            background: var(--white);
        }

        .house::before {
            content: "";
            position: absolute;
            bottom: 39px;
            width: 40px;
            height: 25px;
            clip-path: polygon(0 100%, 50% 0, 100% 100%);
            background: var(--white);
            z-index: 2;
        }

        .house::after {
            content: "";
            position: absolute;
            bottom: 40px;
            width: 50px;
            height: 31px;
            clip-path: polygon(0 100%, 50% 0, 100% 100%);
            background: var(--red);
            z-index: 1;
        }

        .window {
            transform: translateY(-10px);
            height: 6.5px;
            width: 5.2px;
            background: var(--brown);
            z-index: 3;
            border-radius: 1px;
            box-shadow: 12px 12px var(--brown), -12px 12px var(--brown), 0px 12px var(--brown), -12px 24px var(--brown), 0px 24px var(--brown), 12px 24px var(--brown);
        }

        .window::before {
            content: "";
            position: absolute;
            width: 12px;
            height: 18px;
            background: var(--red);
            border-radius: 1px;
            z-index: 2;
            transform: translateY(24px) translateX(-2.6px);
        }

        .snow {
            position: absolute;
            background: var(--white);
            border-radius: 50%;
            opacity: .7;
            height: 2px;
            width: 2px;
        }

        span {
            position: absolute;
            top: 10px;
            right: 12px;
            color: var(--white);
            font-size: 18px;
            letter-spacing: 1px;
            font-family: "Dancing Script", cursive;
        }

        span::before {
            content: "";
            position: absolute;
            height: 18px;
            width: 18px;
            border-radius: 50%;
            transform: translateX(-220px) translateY(20px);
            background: var(--white);
            box-shadow: 0 0 14px yellow;
        }

        @media screen and (max-height: 600px) {
            .stamp {
                transform: scale(1.1);
            }
        }
    </style>
</head>

<body>
    <div class='stamp'>
        <div id='innerStamp' class='inner-stamp'>
            <span>你的家乡下雪了吗</span>
            <div class='snow'></div>
            <div class='house'>
                <div class='window'></div>
            </div>
            <div class='house'>
                <div class='window'></div>
            </div>
            <div class='house'>
                <div class='window'></div>
            </div>
            <div class='house'>
                <div class='window'></div>
            </div>
            <div class='house'>
                <div class='window'></div>
            </div>
        </div>
    </div>
    <script>
        innerStamp = document.getElementById("innerStamp");
        for (let i = 0; i < 800; i++) {
            makeSnow();
        }
        function makeSnow() {
            const snow = document.createElement("div");
            snow.classList.add('snow');
            let positionX = Math.random() * (window.innerWidth);
            let positionY = Math.random() * window.innerHeight;
            let speed = Math.random(2);
            snow.style.top = `${positionY}px`;
            snow.style.left = `${positionX}px`;
            function drop() {
                positionY += speed;
                snow.style.top = `${positionY}px`;
                if (positionY > window.innerHeight) {
                    positionY = - 5;
                }
                requestAnimationFrame(drop);
            }
            drop();
            innerStamp.appendChild(snow);
        }
    </script>
</body>

</html>

HTML 结构

  • stamp: 创建一个类名为“stamp”的 div 元素,用于包含整个邮票场景。
  • innerStamp inner-stamp: 包含内部场景的 div 元素,类名为“inner-stamp”。
  • span: 显示文本“你的家乡下雪了吗”。
  • 多个 house 和 window 元素,用于构建房子和窗户。
  • snow: 用于创建雪花效果的 div 元素。

CSS 样式

  • @import url('...');: 导入 Google 字体
  • :root: 定义了一些 CSS 变量,用于页面的背景色、蓝色、红色、白色和棕色。
  • body: 设置页面的高度、显示方式、背景色等。
  • .stamp: 设置邮票的样式,包括尺寸、背景色和定位。
  • .stamp::before 和 .stamp::after: 用于创建邮票的装饰效果,如边框和背景。
  • .inner-stamp: 设置内部场景的样式,包括尺寸、背景渐变和定位。
  • .inner-stamp::before: 用于显示“来自 Hardy 的祝福”文本。
  • .house 和 .window: 用于构建房子和窗户的样式。
  • .snow: 用于创建雪花效果的样式。
  • span: 用于显示文本“你的家乡下雪了吗”及其装饰效果。
  • @media screen and (max-height: 600px): 媒体查询,用于在屏幕高度小于 600px 时调整邮票的尺寸。

JavaScript 部分

  • makeSnow 函数: 创建雪花效果,通过随机生成雪花的位置和速度,并使用 requestAnimationFrame 实现雪花的下落动画。
  • for 循环: 生成 800 个雪花,调用 makeSnow 函数。