HTML&CSS&JS:卡片3D倾斜效果

这个 HTML 文件实现了一个 3D 效果的图片卡片交互效果,当鼠标悬停在卡片上时,卡片会根据鼠标位置产生 3D 倾斜效果,并显示一个高光反射效果。


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

演示效果

HTML&CSS

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>卡片3D倾斜效果</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        @property --x {
            syntax: '<number>';
            initial-value: 0;
            inherits: true;
        }

        @property --y {
            syntax: '<number>';
            initial-value: 0;
            inherits: true;
        }

        @layer reset {
            * {
                margin: 0;
            }

            svg,
            img {
                display: block;
            }
        }

        .visually-hidden {
            position: fixed;
            top: -999vh;
            left: -999vw;
            pointer-events: none;
        }

        main {
            display: grid;
            grid: auto-flow / repeat(auto-fit, 300px);
            gap: 30px;
            place-items: center;
            place-content: center;
            height: 100vh;
            background:radial-gradient(#424242 0 1px, #0000 1px 10px) 0 / 1em 1em,linear-gradient(#EDEEEE, #E0E0E0)
        }

        .card {
            width: 300px;
            aspect-ratio: 9/12;
            perspective: 1200px;
            transform-style: preserve-3d;
        }

        figure {
            --atan: calc(-1 * atan2(var(--x), var(--y)));
            position: relative;
            height: 100%;
            border-radius: 1em;
            transform: rotateX(calc(var(--x) * 1deg)) rotateY(calc(var(--y) * 1deg));
            overflow: hidden;
            will-change: transform;
            transition: --x 400ms ease,--y 400ms ease;
        }

        figure:hover {
            transition-duration: 0s;
        }

        figure:hover::after {
            opacity: 1;
        }

        figure::after {
            content: '';
            position: absolute;
            inset: 0;
            background: url('https://images.unsplash.com/photo-1615715874901-ad6a07ec5c88?crop=entropy&cs=srgb&fm=jpg&ixid=M3wzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3NTQ0MjE2ODd8&ixlib=rb-4.1.0&q=85') center / cover;
            mask-image: conic-gradient(from var(--atan), #0000, #fffa, #0000, #fffa, #0000);
            backdrop-filter: url(#filterEdges);
            opacity: 0;
            mix-blend-mode: plus-lighter;
            transition: opacity 200ms;
        }

        figure img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }
    </style>
</head>

<body>
    <svg width="0" height="0">
        <defs>
            <filter id="filterEdges">
                <feConvolveMatrix kernelMatrix="0 1 0 1 -4 1 0 1 0" order="3 3" bias="0" divisor="1"
                    preserveAlpha="true" />
            </filter>
        </defs>
    </svg>

    <main>
        <div class="card">
            <figure>
                <img src="https://images.unsplash.com/photo-1579783928621-7a13d66a62d1?crop=entropy&cs=srgb&fm=jpg&ixid=M3wzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3NTQ0MDUyNDN8&ixlib=rb-4.1.0&q=85"
                    alt="">
            </figure>
        </div>
        <div class="card">
            <figure>
                <img src="https://images.unsplash.com/photo-1575396574188-ccf23d32d4b8?crop=entropy&cs=srgb&fm=jpg&ixid=M3wzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3NTQ0ODM3MTN8&ixlib=rb-4.1.0&q=85"
                    alt="">
            </figure>
        </div>
    </main>
    <script>
        const cards = document.querySelectorAll('.card');
        let mouseEnterTarget = null;
        let targetBounds = null;
        function handleMouseEnter(e) {
            mouseEnterTarget = e.target;
            targetBounds = e.target.getBoundingClientRect();
            mouseEnterTarget.addEventListener('mousemove', handleMouseMove);
            mouseEnterTarget.addEventListener('mouseleave', handleMouseLeave);
        }
        function handleMouseLeave(e) {
            mouseEnterTarget.style.setProperty('--x', 0);
            mouseEnterTarget.style.setProperty('--y', 0);
            mouseEnterTarget.removeEventListener('mousemove', handleMouseMove);
        }
        function handleMouseMove(e) {
            const { offsetX, offsetY } = e;
            const centerX = offsetX - (targetBounds.width * 0.5);
            const centerY = offsetY - (targetBounds.height * 0.5);
            const posX = Math.round(-1 * centerX * 0.1);
            const posY = Math.round(centerY * 0.1);
            mouseEnterTarget.style.setProperty('--x', posY);
            mouseEnterTarget.style.setProperty('--y', posX);
        }
        cards.forEach(card => {
            card.addEventListener('mouseenter', handleMouseEnter);
        })
    </script>
</body>

</html>

HTML

  • svg:定义了一个滤镜效果,用于创建边缘高光效果
  • main:作为主容器,包含两个.card 元素
  • 每个.card 包含一个 figure 和 img,显示来自 Unsplash 的图片

CSS

CSS 变量和属性定义

  • 使用@property 定义了--x 和--y 两个自定义属性,用于控制 3D 旋转
  • 这些属性有初始值 0,并支持动画过渡效果

布局样式

  • 主容器使用 CSS Grid 布局,自动适应不同屏幕尺寸
  • 卡片固定宽度 300px,保持 9:12 的宽高比

3D 效果

  • .card 设置了 perspective: 1200px 和 transform-style: preserve-3d 创建 3D 空间
  • figure 元素使用 rotateX 和 rotateY 根据--x 和--y 变量进行 3D 旋转
  • 使用 will-change: transform 优化动画性能

高光效果

  • 通过::after 伪元素创建高光效果
  • 使用 conic-gradient 创建基于角度的遮罩
  • backdrop-filter 应用 SVG 定义的边缘滤镜效果
  • mix-blend-mode: plus-lighter 增强高光效果

JavaScript

事件监听

  • 为每个卡片添加 mouseenter 事件监听
  • 进入时添加 mousemove 和 mouseleave 监听

鼠标移动处理

  • 计算鼠标相对于卡片中心的位置
  • 将位置转换为旋转角度(--x 和--y 值)
  • 这些值会通过 CSS 变量传递给 CSS,实现 3D 旋转效果

鼠标离开处理

  • 重置旋转角度为 0
  • 移除 mousemove 事件监听

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

相关推荐
Zuckjet_10 小时前
开启 3D 之旅 - 你的第一个 WebGL 三角形
前端·javascript·3d·webgl
2401_8638014610 小时前
探索 12 种 3D 文件格式:综合指南
前端·3d
珍宝商店11 小时前
前端老旧项目全面性能优化指南与面试攻略
前端·面试·性能优化
bitbitDown11 小时前
四年前端分享给你的高效开发工具库
前端·javascript·vue.js
YAY_tyy11 小时前
【JavaScript 性能优化实战】第六篇:性能监控与自动化优化
javascript·性能优化·自动化
gnip12 小时前
实现AI对话光标跟随效果
前端·javascript
脑花儿13 小时前
ABAP SMW0下载Excel模板并填充&&剪切板方式粘贴
java·前端·数据库
闭着眼睛学算法14 小时前
【华为OD机考正在更新】2025年双机位A卷真题【完全原创题解 | 详细考点分类 | 不断更新题目 | 六种主流语言Py+Java+Cpp+C+Js+Go】
java·c语言·javascript·c++·python·算法·华为od
烛阴14 小时前
【TS 设计模式完全指南】构建你的专属“通知中心”:深入观察者模式
javascript·设计模式·typescript
lumi.14 小时前
Vue.js 从入门到实践1:环境搭建、数据绑定与条件渲染
前端·javascript·vue.js