HTML&CSS :惊艳 UI 必备!卡片堆叠动画

这个HTML文件,核心目的是展示 "卡片堆叠 + 平滑滚动" 的高级视觉效果,适合前端新手学习HTML、CSS、GSAP 滚动动画。


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

演示效果

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>高级卡片堆叠效果</title>
    <!-- 1. 核心库 -->
    <script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js"></script>
    <!-- 2. 会员插件(含 ScrollSmoother) -->
    <script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/ScrollSmoother.min.js"></script>
    <!-- 3. ScrollTrigger 插件 -->
    <script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/ScrollTrigger.min.js"></script>
    <!-- 引入字体 -->
    <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&family=Playfair+Display:wght@700;800&display=swap" rel="stylesheet">
    <style>
        :root {
            --black: #0f0f0f;
            --dark-gray: #1a1a1a;
            --white: #fff;
            --primary: #6c5ce7;
            --secondary: #a29bfe;
            --accent1: #fd79a8;
            --accent2: #00cec9;
            --accent3: #ffeaa7;
            --text-dark: #2d3436;
            --text-light: #dfe6e9;
        }

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

        body {
            background-color: var(--black);
            color: var(--text-light);
            font-family: 'Montserrat', sans-serif;
            line-height: 1.6;
            overflow-x: hidden;
        }

        main {
            padding: 3.125rem 0;
        }

        h1 {
            color: var(--white);
            font-family: 'Playfair Display', serif;
            font-size: clamp(3.125rem, 17.321vw + -1.357rem, 12.5rem);
            line-height: clamp(4.688rem, 21.363vw + -0.84rem, 16.25rem);
            margin: 6.25rem 0;
            text-align: center;
            text-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
            position: relative;
            z-index: 10;
        }

        h1::after {
            content: "";
            position: absolute;
            bottom: -20px;
            left: 50%;
            transform: translateX(-50%);
            width: 100px;
            height: 4px;
            background: linear-gradient(to right, var(--accent1), var(--accent2));
            border-radius: 2px;
        }

        h2 {
            font-family: 'Playfair Display', serif;
            font-size: clamp(1.8rem, 2.5vw, 2.8rem);
            line-height: 1.2;
            margin-bottom: 1rem;
            color: var(--text-dark);
            position: relative;
            display: inline-block;
        }

        h2::after {
            content: "";
            position: absolute;
            bottom: -8px;
            left: 0;
            width: 50px;
            height: 3px;
            background: linear-gradient(to right, var(--primary), var(--secondary));
            border-radius: 2px;
        }

        .stacking {
            position: relative;
            margin: 10vh 0;
        }

        .stacking__card {
            background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
            border-radius: 20px;
            color: var(--text-dark);
            display: flex;
            flex-direction: column;
            gap: 1.5rem;
            margin: 25vh auto;
            max-width: 800px;
            padding: 2.5rem;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15), 0 15px 30px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease;
            transform-origin: center top;
            position: relative;
            overflow: hidden;
        }

        .stacking__card::before {
            content: "";
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 6px;
            background: linear-gradient(to right, var(--primary), var(--secondary));
        }

        .stacking__card:nth-child(2) {
            background: linear-gradient(135deg, #d6e684 0%, #bdc677 100%);
        }

        .stacking__card:nth-child(3) {
            background: linear-gradient(135deg, #84e6d6 0%, #67bdc6 100%);
        }

        .stacking__card:nth-child(4) {
            background: linear-gradient(135deg, #4fc1ed 0%, #3aa8d0 100%);
        }

        .stacking__content {
            font-size: 1.1rem;
            padding-bottom: 0.5rem;
        }

        .stacking__content p {
            margin-bottom: 1.2rem;
        }

        .container {
            max-width: 800px;
            margin: 0 auto;
            padding: 2rem;
            background-color: var(--dark-gray);
            border-radius: 20px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            position: relative;
            z-index: 5;
        }

        p {
            margin: 1.25rem 0;
            font-size: 1.1rem;
        }

        .container p:first-child::first-letter {
            font-size: 3rem;
            font-weight: bold;
            color: var(--secondary);
            font-family: 'Playfair Display', serif;
            float: left;
            line-height: 1;
            margin-right: 0.5rem;
        }

        /* 响应式设计 */
        @media (max-width: 900px) {
            .stacking__card {
                max-width: 90%;
                margin: 15vh auto;
                padding: 1.8rem;
            }
            
            .container {
                max-width: 90%;
                padding: 1.5rem;
            }
            
            h1 {
                margin: 4rem 0;
            }
        }

        @media (max-width: 600px) {
            .stacking__card {
                padding: 1.5rem;
            }
            
            h2 {
                font-size: 1.6rem;
            }
            
            .stacking__content {
                font-size: 1rem;
            }
        }
    </style>
</head>

<body>
    <main>
        <h1>高级卡片堆叠</h1>
        <div class="stacking">
            <div class="stacking__card">
                <h2>创意设计</h2>
                <div class="stacking__content">
                    <p>探索无限可能的设计理念,将您的想法转化为令人惊叹的视觉体验。我们专注于创造既美观又实用的解决方案。</p>
                    <p>每一个细节都经过精心雕琢,确保为用户提供无缝且愉悦的体验。</p>
                </div>
            </div>
            <div class="stacking__card">
                <h2>用户体验</h2>
                <div class="stacking__content">
                    <p>以用户为中心的设计方法,确保您的产品不仅外观出众,而且易于使用。我们从用户的角度出发,优化每一个交互细节。</p>
                    <p>通过深入的调研和测试,我们创建直观且高效的界面,提升用户满意度和参与度。</p>
                </div>
            </div>
            <div class="stacking__card">
                <h2>技术创新</h2>
                <div class="stacking__content">
                    <p>利用最新的技术趋势和工具,我们构建强大而灵活的解决方案。从响应式设计到高性能代码,我们确保您的项目处于技术前沿。</p>
                    <p>不断创新和改进是我们的核心理念,帮助您在竞争激烈的市场中保持领先。</p>
                </div>
            </div>
            <div class="stacking__card">
                <h2>成果展示</h2>
                <div class="stacking__content">
                    <p>见证我们工作的卓越成果。从概念到实现,我们与客户紧密合作,提供超出期望的最终产品。</p>
                    <p>我们的作品集展示了多样化的项目和行业,证明了我们适应不同需求和挑战的能力。</p>
                </div>
            </div>
        </div>

        <section class="container">
            <p>在现代网页设计中,滚动效果和交互动画已成为吸引用户注意力的关键因素。通过精心设计的卡片堆叠效果,我们可以创建出既视觉惊艳又功能强大的用户界面。</p>
            <p>这种设计模式特别适合展示产品特性、服务项目或作品集,因为它允许在有限的屏幕空间内呈现大量信息,同时保持页面的整洁和直观。</p>
            <p>平滑的滚动效果和渐进的动画转换不仅提升了用户体验,还赋予了网站一种高端和专业的感觉。通过使用GSAP等现代JavaScript动画库,我们可以实现流畅的性能和跨浏览器兼容性。</p>
            <p>响应式设计确保这种效果在各种设备上都能完美呈现,从桌面显示器到移动设备,为用户提供一致的体验。</p>
        </section>
    </main>

    <script>
        gsap.registerPlugin(ScrollTrigger, ScrollSmoother);

        ScrollSmoother.create({
            smooth: 1,
            effects: true,
            normalizeScroll: true
        });

        const cards = gsap.utils.toArray(".stacking__card");
        const spacer = 50;

        cards.forEach((card, index) => {
            ScrollTrigger.create({
                trigger: card,
                start: `center-=${index * spacer} center`,
                endTrigger: ".stacking",
                end: `bottom center`,
                pin: true,
                pinSpacing: false,
                // markers: true, // 取消注释可显示滚动触发器标记
                invalidateOnRefresh: true
            });

            const scaleValue = 0.85 + index * 0.05;
            gsap.to(card, {
                scrollTrigger: {
                    trigger: card,
                    start: `top center`,
                    end: `bottom center`,
                    scrub: true,
                    // markers: true, // 取消注释可显示滚动触发器标记
                    invalidateOnRefresh: true
                },
                scale: scaleValue
            });
        });
    </script>
</body>

</html>

HTML

  • h1:页面主标题
  • .stacking:容器4 张 .stacking__card
  • .container:段落区(用来撑开后续滚动空间,让卡片能被"钉"住)
  • .stacking__card:每张卡片盒子
  • h2 小标题
  • .stacking__content 段落文字

CSS

  • root:定义了两组调色盘:深色背景系列(black/dark-gray)和 渐变强调色(primary、secondary、accent1~3)

  • 全局重置:*{margin:0;padding:0;box-sizing:border-box} 经典起手式。body 设 overflow-x:hidden 防止横向滚动条。

  • h1 使用 clamp() 实现流畅响应式字号;

  • ::after 用 100×4px 的渐变色条做"下划线"装饰。

  • h2 同样用 clamp(),并带 50×3px 的左侧渐变条。

  • .stacking:position:relative 给后续"钉住"卡片当定位父级。

  • .stacking__card:白→灰渐变背景,统一圆角、阴影、顶部 6px 高亮色条。通过 :nth-child(2~4) 分别覆盖成黄绿/青绿/天蓝渐变,形成视觉区分。

  • transform-origin:center top 为后面 GSAP 缩放做准备。

  • 900px 以下:卡片宽度 90%、上下 margin 缩小。

  • 600px 以下:继续压 padding 与字号,保证移动端不拥挤。

JavaScript 逻辑部分

注册插件

gsap.registerPlugin(ScrollTrigger, ScrollSmoother);

启用平滑滚动

JavaScript 复制代码
ScrollSmoother.create({
    smooth: 1,        // 平滑度(0=关,1=最平滑)
    effects: true,    // 允许 data-speed 等声明式速度
    normalizeScroll: true // 统一不同浏览器的滚动速度
});

卡片"堆叠钉住"效果

思路:

  • 把每张卡看成独立的"钉"(pin)对象。
  • 越早出现的卡片,越早被钉住;后续卡片从它身上"滑"过去。
  • 通过 pinSpacing:false 让多张卡片共享同一段滚动距离,形成叠罗汉。

具体步骤:

a) 取全部卡片 gsap.utils.toArray(".stacking__card")

b) 循环 cards.forEach((card, index)=>{ ... }) -- 创建 ScrollTrigger

  • trigger: card
  • start: "center-=${index*spacer} center"

越早的卡片,触发中心点越往上移(spacer=50px)。

  • endTrigger: ".stacking"
  • end: "bottom center"

一直到 .stacking 容器底部才释放。

  • pin:true, pinSpacing:false → 关键:钉住但不额外占高度。

c) 同时再加一条"缩放"动画

让卡片在滚动过程中由 1 → scaleValue 缩小, scaleValue 公式:0.85 + index * 0.05

即第 1 张 0.85,第 4 张 1.0,越靠后缩得越少,视觉上层级更高。

使用 scrub:true 让缩放与滚动进度同步。


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

相关推荐
无羡仙6 小时前
替代 Object.freeze 的精准只读模式
前端·javascript
web前端1236 小时前
Java客户端开发指南 - 与Web开发对比分析
前端
龙在天6 小时前
前端 9大 设计模式
前端
搞个锤子哟6 小时前
网站页面放大缩小带来的问题
前端
hj5914_前端新手6 小时前
React 基础 - useState、useContext/createContext
前端·react.js
半花6 小时前
【Vue】defineProps、defineEmits 和 defineExpose
前端·vue.js
霍格沃兹_测试6 小时前
软件测试 | 测试开发 | H5页面多端兼容测试与监控
前端
toooooop86 小时前
本地开发环境webScoket调试,保存html即用
前端·css·websocket
山有木兮木有枝_6 小时前
手动封装移动端下拉刷新组件的设计与实现
前端