jym好?,我是月弦笙音,今天给大家分享如何制作可翻转的3D卡片,嘎嘎的?,看下面
引言:在堆业务架子工盛行的时代,请不要忘记咱们大大前端的css动效大法。请牢记一句话:掌握前端原生者掌握未来!!!
转载本文或者代码,请告知我哈?
为了达到这3D而且能翻转的种效果,我们必须在js和CSS中结合一些不同的东西?:
- 首先,我们需要创建一个函数,让我们根据鼠标位置操作卡片的角度。✔
- 接下来,我们需要使用该函数来确定在卡片顶部添加“眩光”光效果的位置。✔
- 然后,我们需要添加大量的 CSS 来为卡片创建一个背面和一个正面。✔
- 最后,我们需要在 js 中添加一些函数来允许我们“翻转”卡片。✔
-
欢迎上手先体验一把,畅享丝滑:?
-
可翻转的3D卡片体验地址:code.juejin.cn/pen/7243644…
开始介绍 + 编码:
一、敲写html?
让我们从 HTML 开始。这是我们第一张卡片(卡片广告的内容,建议jym也可以去学习,干货满满!)的外观。每张卡有两个主要部分 。第一个包含卡片的正面,第二个包含背面。inner-card``inner-card-backface
- 正面:?
- 反面:?
我们还有两个按钮,点击 – 翻转和取消翻转,会以3D过渡的形式以更改卡片的哪一侧可见。
<div class="card blastoise">
<span class="inner-card-backface"> <!-- back of the card -->
<span class="image">
<span class="unflip">Unflip</span>
</span>
</span>
<span class="inner-card"> <!-- front of the card -->
<span class="flip">Flip</span>
<span class="glare"></span> <!-- to store the glare effect -->
</span>
</div>
二、创建 JS?
我们的JS做了一件基本的事情那就找出用户在卡片上的位置
,并将其转换为我们传递给CSS的角度,以改变我们查看卡片的方式。为此,我们需要了解用户离卡中心有多远
。我们实际上只有两个轴需要担心 当用户到达任何一个轴的顶部或底部时
,我们可以相对于中心旋转卡片,如下图所示,我用红线标出来了,意思你应该明白?
了解上图的用户旋转角度后,最终,为此情景,我们编写了一个接受“card”元素的函数,并相应地更新其CSS,如下所示:?
let dropShadowColor = `rgba(0, 0, 0, 0.3)`
if (parent.getAttribute('data-filter-color') !== null) {
dropShadowColor = parent.getAttribute('data-filter-color');
}
parent.classList.add('animated');
// 获取用户鼠标相对于按钮本身的x位置
let x = Math.abs(item.getBoundingClientRect().x - e.clientX);
// 获取相对于按钮的y位置
let y = Math.abs(item.getBoundingClientRect().y - e.clientY);
// 计算宽度和高度的一半
let halfWidth = item.getBoundingClientRect().width / 2;
let halfHeight = item.getBoundingClientRect().height / 2;
//创建一个角度。我已经分别除以6和4,所以效果看起来很好。
//改变这些数字将改变效果的深度。
let calcAngleX = (x - halfWidth) / 6;
let calcAngleY = (y - halfHeight) / 14;
let gX = (1 - (x / (halfWidth * 2))) * 100;
let gY = (1 - (y / (halfHeight * 2))) * 100;
item.querySelector('.glare').style.background = `radial-gradient(circle at ${gX}% ${gY}%, rgb(199 198 243), transparent)`;
// 并设置其容器的视角。
parent.style.perspective = `${halfWidth * 6}px`
item.style.perspective = `${halfWidth * 6}px`
// 设置项目转换CSS属性
item.style.transform = `rotateY(${calcAngleX}deg) rotateX(${-calcAngleY}deg) scale(1.04)`;
parent.querySelector('.inner-card-backface').style.transform = `rotateY(${calcAngleX}deg) rotateX(${-calcAngleY}deg) scale(1.04) translateZ(-4px)`;
if (parent.getAttribute('data-custom-perspective') !== null) {
parent.style.perspective = `${parent.getAttribute('data-custom-perspective')}`
}
// 重新应用到阴影上,使用不同的分割线
let calcShadowX = (x - halfWidth) / 3;
let calcShadowY = (y - halfHeight) / 6;
// 添加一个滤镜阴影——这比普通的框阴影更能表现动画效果。
item.style.filter = `drop-shadow(${-calcShadowX}px ${-calcShadowY}px 15px ${dropShadowColor})`;
}
这个函数做 4 件事?
-
- 计算元素的阴影,使其看起来在 3D 空间中移动。✔
-
- 根据鼠标位置计算卡应处于的角度。✔
-
- 计算背面的位置,使其与卡的卡正面一起移动。✔
-
- 计算眩光的位置,即用户鼠标所在位置的反射。✔
所以,我们现在要做的就是将这个函数添加到每个鼠标移动事件中
,然后在用户的鼠标离开元素时重置所有内容。我们还将添加一些用于“翻转”和“取消翻转”卡的功能:?
if (item.querySelector('.flip') !== null) {
item.querySelector('.flip').addEventListener('click', function () {
item.classList.add('flipped');
});
}
if (item.querySelector('.unflip') !== null) {
item.querySelector('.unflip').addEventListener('click', function () {
item.classList.remove('flipped');
});
}
item.addEventListener('mouseenter', function (e) {
calculateAngle(e, this.querySelector('.inner-card'), this);
});
item.addEventListener('mousemove', function (e) {
calculateAngle(e, this.querySelector('.inner-card'), this);
});
item.addEventListener('mouseleave', function (e) {
let dropShadowColor = `rgba(0, 0, 0, 0.3)`
if (item.getAttribute('data-filter-color') !== null) {
dropShadowColor = item.getAttribute('data-filter-color')
}
item.classList.remove('animated');
item.querySelector('.inner-card').style.transform = `rotateY(0deg) rotateX(0deg) scale(1)`;
item.querySelector('.inner-card-backface').style.transform = `rotateY(0deg) rotateX(0deg) scale(1.01) translateZ(-4px)`;
item.querySelector('.inner-card').style.filter = `drop-shadow(0 10px 15px ${dropShadowColor})`;
});
})
你可能会注意到鼠标事件是针对卡的,但转换主要发生在 .inner-card
上。这是因为,如果 .card 的角度发生变化,“悬停框”也会发生变化。如果发生这种情况,用户可能会将鼠标悬停在卡片上,但角度会变化很大,以至于他们不会再改变,使效果看起来很糟糕。通过向卡添加悬停效果,我们保持了一个恒定的悬停框,同时仍然允许我们在这个固定框中转换 .inner-card
。?
三、添加 CSS
最后,我们可以添加 CSS。这里的基本问题是,我们有一个卡容器.card,其中包含我们转换的卡 – .inner-card
。?
以这种方式做事的另一个好处是,当用户单击“翻转”时,我们可以翻转自己,因为我们维护一个父元素和子元素。这意味着我们可以继续转换和翻转 .card,同时产生更无缝的效果。.card``.inner-card,
?
在 上,我们添加行以将其向后移动 4 个像素。这创造了一个很酷的3D深度效果,并确保正面和背面在用户悬停时不会发生碰撞。我们还添加到我们的 .card 中,因此我们的背面和正面都可以交互。.inner-card-backface``transform: rotateX(0) rotateY(0deg) scale(1) translateZ(-4px);``backface-visibility: visible;
?
最后,由于我们使用 .flipped
类翻转整个卡片,因此我们需要“解翻”卡片背面的内容。如果我们不这样做,背面的文字将从后到前显示!所以我们有一个类,它只是让我们翻转卡片的背面.flip-inner-card
?
css如下所示:?
.card {
box-shadow: none;
backface-visibility: visible;
background: transparent;
font-family: Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;
transform-style: preserve-3d;
padding: 0;
height: auto;
margin: 0 2rem 0 0;
width: 18rem;
height: 25rem;
float: left;
transition: all 0.2s ease-out;
border: none;
letter-spacing: 1px;
}
.flip, .unflip {
background: rgba(0,0,0,0.1);
font-size: 1rem;
position: absolute;
top: 1rem;
right: 1rem;
padding: 0.5rem 0.75rem;
border-radius: 100px;
line-height: 1rem;
cursor: pointer;
transition: all 0.1s ease-out;
}
.unflip {
top: auto;
background: #2d2d62;
bottom: 1rem;
}
.flip:hover {
background: rgba(0,0,0,0.3);
}
.card .flip-inner-card {
transform: rotateY(180deg);
position: absolute;
top: 0;
padding: 2rem 1.5rem;
box-sizing: border-box;
left: 0;
width: 100%;
height: 100%;
}
.inner-card-backface {
transform: rotateX(0) rotateY(0deg) scale(1) translateZ(-4px);
border-radius: 14px;
background: linear-gradient(45deg, #0b0b2a, #0b0b2a);
position: absolute;
top: 0;
color: white;
padding: 2rem;
box-sizing: border-box;
transition: all 0.15s ease-out;
will-change: transform, filter;
left: 0;
width: 100%;
height: 100%;
}
.card.flipped {
transform: rotateY(180deg);
}
.card .flip-inner-card {
transform: rotateY(180deg);
position: absolute;
top: 0;
padding: 2rem 1.5rem;
box-sizing: border-box;
left: 0;
width: 100%;
height: 100%;
}
四、结语❤
在本教程中,我介绍了如何制作 3d CSS 可翻转卡片。我们已经讨论了确定用户将鼠标悬停在上面时显示的角度所需的函数,以及制作这样的 3D 卡片所需的 CSS。希望jym喜欢它 – 随意在你的任何个人项目中使用它。?
感谢jym浏览本文,共同进步?,若有更好的建议,欢迎评论区讨论哈?。
如果jym觉得这篇干货很有用,可以加个关关?,点个赞赞?,后面我会继续卷,分享更多干货!感谢支持!?