HTML&CSS:高颜值视差滚动3D卡片

这个 HTML 文件创建了一个视觉效果精美的宣传卡片,具有视差滚动和 3D 效果。


大家复制代码时,可能会因格式转换出现错乱,导致样式失效。建议先少量复制代码进行测试,若未能解决问题,私信回复源码两字,我会发送完整的压缩包给你。

演示效果

HTML&CSS

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>关注公众号:前端Hardy</title>
    <style>
        :root {
            --title: "Parallax Bake Shop Card";
            --author: "Matt Cannon";
            --contact: "[email protected]";
            --description: "A whimsical bake shop card with a cupcake theme, parallax effects, dreamy text, and floating background layers.";
            --keywords: "cupcake animation, sweet treats, parallax effect, css animation, javascript, food theme, codepenchallenge, bakery banner, interactive header, dessert ui, creative design";
            --last-modified: "2025-05-27";
            --content-language: "en";
            --generator: "HTML5, CSS3, JavaScript, Web Animations API";
        }

        *,
        *:after,
        *:before {
            box-sizing: border-box;
        }

        :root {
            --x: 0;
            --y: 0;
        }

        html {
            color-scheme: light only;
        }

        body {
            display: flex;
            place-items: center;
            justify-content: center;
            min-height: 100svh;
            touch-action: none;
            font-family: "Rubik", sans-serif;
            margin: 0;
            padding: 0.5rem;
            background: linear-gradient(to bottom, #e68d9f, #ffffff),
                url("https://www.transparenttextures.com/patterns/asfalt-light.png");
            background-blend-mode: overlay;
        }

        article {
            width: 600px;
            aspect-ratio: 2 / 1.1;
            max-height: calc(100svh - 2rem);
            position: relative;
            overflow: hidden;
            border-radius: 4em;
            max-width: calc(100% - 2rem);
            filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.1));
        }

        @media (orientation: portrait) {
            article {
                min-height: 330px;
            }
        }

        .assets {
            position: absolute;
            inset: 0;
            border-radius: 4em;
            overflow: hidden;
            z-index: 0;
        }

        .assets>img {
            position: absolute;
            top: 0;
            left: 50%;
            translate: -50% 0;
            height: 100%;
            width: 660px;
            object-fit: cover;
            object-position: center 43%;
            user-select: none;
            pointer-events: none;
        }

        .assets>img:first-of-type {
            filter: saturate(1.5) brightness(0.9);
            object-position: calc(50% + (var(--x) * 30px)) calc(50% + (var(--y) * -20px));
        }

        .assets>img:last-of-type {
            object-position: calc(50% + (var(--x) * 40px)) calc(50% + (var(--y) * 10px));
            z-index: 99;
        }

        .assets h3 {
            position: absolute;
            left: 50%;
            top: 8%;
            margin: 0;
            font-size: 8rem;
            text-transform: uppercase;
            font-family: "Bebas Neue", sans-serif;
            color: white;
            translate: calc(-50% + (var(--x) * -30px)) calc(var(--y) * -20px);
            z-index: 4;
        }

        .content {
            min-height: 32%;
            position: absolute;
            bottom: 0;
            width: 100%;
            color: white;
            display: grid;
            gap: 0.2rem;
            place-items: center;
            align-content: center;
            padding-bottom: 0.5rem;
            z-index: 3;
        }

        .content svg {
            width: 20px;
        }

        .content p {
            margin: 0;
            display: flex;
            align-items: center;
            gap: 0.5rem;
            font-size: 1.2rem;
            position: relative;
        }

        .content p:first-of-type::after {
            content: "";
            position: absolute;
            bottom: calc(100% + 1rem);
            left: 50%;
            width: 20ch;
            background: white;
            height: 1px;
            translate: -50% 0;
        }

        .content p:last-of-type {
            opacity: 0.8;
            font-size: 0.8rem
        }

        .blur {
            --layers: 5;
            position: absolute;
            inset: 0;
            z-index: 1;
        }

        .blur .layer {
            --blur: calc(sin(((var(--layers) - var(--index)) / var(--layers)) * 90deg) * 5);
            --stop: calc(sin(((var(--index)) / var(--layers)) * 90deg) * 25);
            position: absolute;
            inset: 0;
            background: hsl(0 0% 60% / 0.015);
            backdrop-filter: blur(min(calc(var(--blur) * 1px), 4px));
            mask: radial-gradient(180% 160% at 45% 90%,
                    #fff 10%,
                    #0000 calc((10 + var(--stop)) * 1%));
            z-index: 2;
        }
    </style>
</head>

<body>
    <article>
        <div class="assets">
            <img src="http://mattcannon.games/codepen/sweet-treats/bg.webp" alt="Background clouds" />
            <h3>CUPCAKES</h3>
            <img src="http://mattcannon.games/codepen/sweet-treats/cup-cake.png" alt="Cupcake"
                style="width: 200px; height: 250px;" />
        </div>
        <div class="blur">
            <div class="layer" style="--index:1;"></div>
            <div class="layer" style="--index:2;"></div>
            <div class="layer" style="--index:3;"></div>
            <div class="layer" style="--index:4;"></div>
            <div class="layer" style="--index:5;"></div>
        </div>
        <div class="content">
            <p>
                <i class="fas fa-map-marker-alt"></i>
                Sweet Dreams Bakery
            </p>
            <p><i>Los Angeles, CA</i></p>
        </div>
    </article>
    <script>
        const UPDATE = ({ x, y }) => {
            const xNorm = (x / window.innerWidth - 0.5) * 2;
            const yNorm = (y / window.innerHeight - 0.5) * 2;
            document.documentElement.style.setProperty("--x", xNorm);
            document.documentElement.style.setProperty("--y", yNorm);
        };

        window.addEventListener("mousemove", UPDATE);
        const handleOrientation = ({ beta, gamma }) => {
            const isLandscape = window.matchMedia("(orientation: landscape)").matches;
            const xVal = Math.max(
                -1,
                Math.min(1, isLandscape ? (beta || 0) / 45 : (gamma || 0) / 45)
            );
            const yVal = Math.max(
                -1,
                Math.min(1, isLandscape ? Math.abs(gamma || 0) / 45 : (beta || 0) / 45)
            );

            document.documentElement.style.setProperty("--x", xVal);
            document.documentElement.style.setProperty("--y", yVal);
        };
        const START = () => {
            if (DeviceOrientationEvent?.requestPermission) {
                DeviceOrientationEvent.requestPermission().then((result) => {
                    if (result === "granted") {
                        window.addEventListener("deviceorientation", handleOrientation);
                    }
                });
            } else {
                window.addEventListener("deviceorientation", handleOrientation);
            }
        };
        document.body.addEventListener("click", START, { once: true });
    </script>
</body>

</html>

HTML 结构

  • 整个页面以一个卡片为中心,使用 article 标签作为主要容器。
  • 卡片内部有三个主要部分:.assets、.blur 和.content。
  • .assets 部分包含两张背景图片和标题文字。
  • .blur 部分使用多个层创建模糊渐变效果。
  • .content 部分显示店铺名称和位置信息。

CSS 关键部分

  • 视差效果:通过--x 和--y 变量控制不同元素的移动速度,实现 3D 视差效果。
  • 背景处理:使用多层背景图片叠加,结合 object-position 和 CSS 变量实现动态效果。
  • 模糊渐变:.blur 类中的多个层使用 backdrop-filter: blur()和 mask 属性创建从中心到边缘的渐变模糊效果。
  • 响应式设计:使用媒体查询处理不同屏幕方向的显示效果,确保在移动设备上也能良好展示。
  • 变量定义:使用 CSS 变量存储视差位移值,方便 JavaScript 控制。

JavaScript 功能

  • 鼠标跟踪:通过 mousemove 事件监听鼠标位置,计算并更新 CSS 变量--x 和--y。
  • 设备方向支持:通过 deviceorientation 事件检测设备倾斜,实现移动设备上的视差效果。
  • 权限处理:在 iOS 设备上,通过 DeviceOrientationEvent.requestPermission()方法请求设备方向权限。
  • 归一化处理:将鼠标位置和设备方向数据归一化为 - 1 到 1 之间的值,确保视差效果在不同设备上的一致性。

各位互联网搭子,要是这篇文章成功引起了你的注意,别犹豫,关注、点赞、评论、分享走一波,让我们把这份默契延续下去,一起在知识的海洋里乘风破浪!

相关推荐
じ☆ve 清风°33 分钟前
JavaScript 原型与原型链:深入理解 __proto__ 和 prototype 的由来与关系
开发语言·javascript·原型模式
又又呢40 分钟前
前端面试题总结——webpack篇
前端·webpack·node.js
dog shit2 小时前
web第十次课后作业--Mybatis的增删改查
android·前端·mybatis
我有一只臭臭2 小时前
el-tabs 切换时数据不更新的问题
前端·vue.js
七灵微2 小时前
【前端】工具链一本通
前端
Nueuis3 小时前
微信小程序前端面经
前端·微信小程序·小程序
_r0bin_5 小时前
前端面试准备-7
开发语言·前端·javascript·fetch·跨域·class
IT瘾君5 小时前
JavaWeb:前端工程化-Vue
前端·javascript·vue.js
zhang98800005 小时前
JavaScript 核心原理深度解析-不停留于表面的VUE等的使用!
开发语言·javascript·vue.js
potender5 小时前
前端框架Vue
前端·vue.js·前端框架