最近在做公司新产品的官网,偶然发现一个特别炫酷的卡片效果效果如下:
自己研究了一下,尝试手动实现一个,以下是实现思路,码上掘金代码片段在最下方👇
第一步:先画一个带阴影的卡片
<div class="card">跟随鼠标移动的3D卡片</div>
第二步:添加css样式
.card {
--rotateX: 0; // rotateX变量
--rotateY: 0; // rotateY变量
--scale3d: 1; // scale3d变量
width: 200px;
height: 300px;
background-color: #007873;
color: #fff;
line-height: 300px;
text-align: center;
border-radius: 8px;
transition: all 0.8s cubic-bezier(0.165, 0.84, 0.44, 1);
box-shadow: 20px 10px 58px rgba(0, 0, 0, 0.3);
transform-style: preserve-3d;
transform: perspective(3000px) rotateY(var(--rotateX)) rotateX(var(--rotateY))
scale3d(var(--scale3d), var(--scale3d), var(--scale3d));
}
transform-style: preserve-3d;
CSS的一个属性,主要用于3D变换。
- 默认值
flat
:元素不会在3D空间中呈现,而是被渲染为平面的,并且没有Z轴变换。 preserve-3d
:元素会在3D空间中呈现,并保留其Z轴变换。具体细节详见MDN
transform
perspective
透视定义了观察者与Z=0平面的距离,它影响元素看起来有多大以及它们如何随着距离变远而变小。具体细节详见MDNrotateY
元素绕纵轴(Y轴)旋转。rotateX
元素绕横轴(X轴)旋转。scale3d
元素3D缩放。
第三步:添加事件,处理元素旋转角度
function setElementRotate(element, rotateX, rotateY, scale3d) {
element.style.setProperty("--rotateX", rotateX + "deg");
element.style.setProperty("--rotateY", rotateY + "deg");
element.style.setProperty("--scale3d", scale3d);
}
function rotateElement(event, element) {
const x = event.clientX;
// clientX 鼠标指针相对于当前窗口的水平坐标
// offsetX 鼠标指针相对于目标元素边缘位置的水平坐标
// 如果元素不在窗口左上角,建议使用 offsetX
// event.offsetX
const y = event.clientY;
// event.offsetY
const middleX = element.clientWidth / 2;
const middleY = element.clientHeight / 2;
const offsetX = ((x - middleX) / middleX) * 10;
const offsetY = ((y - middleY) / middleY) * 10;
setElementRotate(element, offsetX, -1 * offsetY, 1.04);
}
const initRotate = (element) => {
element.addEventListener("mouseenter", function (e) {
rotateElement(e, element);
});
element.addEventListener("mousemove", function (e) {
rotateElement(e, element);
});
element.addEventListener("mouseleave", function () {
setElementRotate(element, 0, 0, 1);
});
};
initRotate(document.querySelector(".card"));
元素mouseenter
mouseleave
事件触发rotateElement
函数执行,rotateElement
通过计算鼠标当前的位置,以及元素宽高的一半
其中旋转的逻辑主要在rotateElement
函数中,以X轴为例:
- -90deg代表元素沿着X轴向左旋转90度,从正面看上去就是一条直线,而需求是卡片能在一个较小的阈值能旋转。
- 我们希望当鼠标在元素的最左侧的时候,得到的值是-1,鼠标在元素最右侧的时候,得到的值是1,鼠标在元素中间位置的时候得到的值是0,这样根据自身需求只需要再✖️一个阈值就可以。
- 假设鼠标移动事件的
event.clientX
为x
,需要得到的值为y
,元素宽度element.clientWidth
为cw
,然后使用AI工具即得如下公式👇
稍微简化一下就是目前代码中的逻辑,10为自定义的阈值,数值越大倾斜角越大
const middleX = element.clientWidth / 2;
const middleY = element.clientHeight / 2;
const offsetX = ((x - middleX) / middleX) * 10;
const offsetY = ((y - middleY) / middleY) * 10;
完结,撒花✿✿ヽ(°▽°)ノ✿,如有不妥请JYM指点🤗
原文链接:https://juejin.cn/post/7356240651040636943 作者:fe_jh