这是一款带视觉倾斜效果的鼠标悬停卡片动画特效。该特效通过js和css3代码,使鼠标悬停在一张图片卡片上面时,卡片会根据鼠标的方向进行3d倾斜.
使用方法
HTML结构
01. Normal
02. Reverse
03. Normal
CSS样式
*,
*::after,
*::before {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 62.5%;
}
body {
--background-color: hsl(180, 20%, 90%);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
min-height: 100vh;
padding: 2rem;
color: hsla(0, 0%, 0%, .6);
background: var(--background-color);
text-align: center;
}
h1 {
font-size: 3.2rem;
padding-top: 2rem;
}
h1+p {
font-size: 1.8rem;
padding: 2rem 0 3rem;
}
.main {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
.wrap {
margin: 2rem;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-transform: perspective(100rem);
transform: perspective(100rem);
cursor: pointer;
}
.container {
--rX: 0;
--rY: 0;
--bX: 50%;
--bY: 80%;
width: 30rem;
height: 36rem;
border: 1px solid var(--background-color);
border-radius: 1.6rem;
padding: 4rem;
display: flex;
align-items: flex-end;
position: relative;
-webkit-transform: rotateX(calc(var(--rX) * 1deg)) rotateY(calc(var(--rY) * 1deg));
transform: rotateX(calc(var(--rX) * 1deg)) rotateY(calc(var(--rY) * 1deg));
/*background: linear-gradient(hsla(0, 0%, 100%, .1), hsla(0, 0%, 100%, .1)), url("https://images.unsplash.com/photo-1559113513-d5e09c78b9dd?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjF9");*/
background: linear-gradient(hsla(0, 0%, 100%, .1), hsla(0, 0%, 100%, .1)), url("../img/photo-1559113513-d5e09c78b9dd.jpg");
background-position: var(--bX) var(--bY);
background-size: 40rem auto;
box-shadow: 0 0 3rem .5rem hsla(0, 0%, 0%, .2);
transition: -webkit-transform .6s 1s;
transition: transform .6s 1s;
transition: transform .6s 1s, -webkit-transform .6s 1s;
}
.container::before,
.container::after {
content: "";
width: 2rem;
height: 2rem;
border: 1px solid #fff;
position: absolute;
z-index: 2;
opacity: .3;
transition: .3s;
}
.container::before {
top: 2rem;
right: 2rem;
border-bottom-width: 0;
border-left-width: 0;
}
.container::after {
bottom: 2rem;
left: 2rem;
border-top-width: 0;
border-right-width: 0;
}
.container--active {
transition: none;
}
.container--2 {
-webkit-filter: hue-rotate(80deg) saturate(140%);
filter: hue-rotate(80deg) saturate(140%);
}
.container--3 {
-webkit-filter: hue-rotate(160deg) saturate(140%);
filter: hue-rotate(160deg) saturate(140%);
}
.container p {
color: hsla(0, 0%, 100%, .6);
font-size: 2.2rem;
}
.wrap:hover .container::before,
.wrap:hover .container::after {
width: calc(100% - 4rem);
height: calc(100% - 4rem);
}
JavaScript
class parallaxTiltEffect {
constructor({element, tiltEffect}) {
this.element = element;
this.container = this.element.querySelector(".container");
this.size = [300, 360];
[this.w, this.h] = this.size;
this.tiltEffect = tiltEffect;
this.mouseOnComponent = false;
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseEnter = this.handleMouseEnter.bind(this);
this.handleMouseLeave = this.handleMouseLeave.bind(this);
this.defaultStates = this.defaultStates.bind(this);
this.setProperty = this.setProperty.bind(this);
this.init = this.init.bind(this);
this.init();
}
handleMouseMove(event) {
const {offsetX, offsetY} = event;
let X;
let Y;
if (this.tiltEffect === "reverse") {
X = ((offsetX - (this.w/2)) / 3) / 3;
Y = (-(offsetY - (this.h/2)) / 3) / 3;
}
else if (this.tiltEffect === "normal") {
X = (-(offsetX - (this.w/2)) / 3) / 3;
Y = ((offsetY - (this.h/2)) / 3) / 3;
}
this.setProperty('--rY', X.toFixed(2));
this.setProperty('--rX', Y.toFixed(2));
this.setProperty('--bY', (80 - (X/4).toFixed(2)) + '%');
this.setProperty('--bX', (50 - (Y/4).toFixed(2)) + '%');
}
handleMouseEnter() {
this.mouseOnComponent = true;
this.container.classList.add("container--active");
}
handleMouseLeave() {
this.mouseOnComponent = false;
this.defaultStates();
}
defaultStates() {
this.container.classList.remove("container--active");
this.setProperty('--rY', 0);
this.setProperty('--rX', 0);
this.setProperty('--bY', '80%');
this.setProperty('--bX', '50%');
}
setProperty(p, v) {
return this.container.style.setProperty(p, v);
}
init() {
this.element.addEventListener('mousemove', this.handleMouseMove);
this.element.addEventListener('mouseenter', this.handleMouseEnter);
this.element.addEventListener('mouseleave', this.handleMouseLeave);
}
}
const $ = e => document.querySelector(e);
const wrap1 = new parallaxTiltEffect({
element: $('.wrap--1'),
tiltEffect: 'reverse'
});
const wrap2 = new parallaxTiltEffect({
element: $('.wrap--2'),
tiltEffect: 'normal'
});
const wrap3 = new parallaxTiltEffect({
element: $('.wrap--3'),
tiltEffect: 'reverse'
});