Install & Download:
Description:
Create responsive cards with hover-triggered parallax effect in Vue.js app.
How to use it:
1. Code the HTML for the cards.
<div id="app" class="container">
<card data-image="https://cdn.pixabay.com/photo/2018/05/27/15/28/technology-3433708_960_720.jpg">
<h1 slot="header">DevOps</h1>
<p slot="content">Hodor. Hodor hodor, hodor. Hodor hodor hodor hodor hodor. Hodor. Hodor! Hodor hodor, hodor; hodor hodor hodor. Hodor.</p>
</card>
<card data-image="https://cdn.pixabay.com/photo/2019/11/23/04/52/matrix-4646234_960_720.jpg">
<h1 slot="header">Machine Learning</h1>
<p slot="content">Hodor. Hodor hodor, hodor. Hodor hodor hodor hodor hodor. Hodor. Hodor! Hodor hodor, hodor; hodor hodor hodor. Hodor.</p>
</card>
<card data-image="https://cdn.pixabay.com/photo/2013/11/20/09/35/background-213649_960_720.jpg">
<h1 slot="header">Data Analytics</h1>
<p slot="content">Hodor. Hodor hodor, hodor. Hodor hodor hodor hodor hodor. Hodor. Hodor! Hodor hodor, hodor; hodor hodor hodor. Hodor.</p>
</card>
...
</div>2. The core CSS styles for the parallax cards.
.container {
padding: 40px 80px;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.card-wrap {
margin: 10px;
transform: perspective(1200px);
transform-style: preserve-3d;
cursor: pointer;
}
.card-wrap:hover .card-info {
transform: translateY(0);
}
.card-wrap:hover .card-info p {
opacity: 1;
}
.card-wrap:hover .card-info, .card-wrap:hover .card-info p {
transition: 0.6s cubic-bezier(0.23, 1, 0.32, 1);
}
.card-wrap:hover .card-info:after {
transition: 3s cubic-bezier(0.23, 1, 0.32, 1);
opacity: 1;
transform: translateY(0);
}
.card-wrap:hover .card-bg {
transition: 0.5s cubic-bezier(0.23, 1, 0.32, 1), opacity 4s cubic-bezier(0.23, 1, 0.32, 1);
opacity: 0.8;
}
.card-wrap:hover .card {
transition: 0.5s cubic-bezier(0.23, 1, 0.32, 1);
box-shadow: none;
}
.card {
position: relative;
flex: 0 0 240px;
width: 320px;
height: 320px;
background-color: #000;
overflow: hidden;
box-shadow: rgba(0, 0, 0, 0.66) 0 30px 60px 0, inset #333 0 0 0 5px, inset rgba(255, 255, 255, 0.4) 0 0 0 6px;
transition: 0.8s cubic-bezier(0.445, 0.05, 0.55, 0.95);
}
.card-bg {
opacity: 0.5;
position: absolute;
top: -20px;
left: -20px;
width: 100%;
height: 100%;
padding: 20px;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
transition: 0.8s cubic-bezier(0.445, 0.05, 0.55, 0.95), opacity 4s 0.8s cubic-bezier(0.445, 0.05, 0.55, 0.95);
pointer-events: none;
}
.card-info {
padding: 20px;
position: absolute;
bottom: 0;
color: #fff;
transform: translateY(40%);
transition: 0.6s 1.6s cubic-bezier(0.215, 0.61, 0.355, 1);
}
.card-info p {
opacity: 0;
text-shadow: black 0 2px 3px;
transition: 0.6s 1.6s cubic-bezier(0.215, 0.61, 0.355, 1);
}
.card-info * {
position: relative;
z-index: 1;
}
.card-info:after {
content: "";
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(to bottom, transparent 0%, rgba(0, 0, 0, 0.6) 100%);
background-blend-mode: overlay;
opacity: 0;
transform: translateY(100%);
transition: 5s 1s cubic-bezier(0.445, 0.05, 0.55, 0.95);
}
.card-info h1 {
font-family: "Raleway", sans-serif;
font-size: 36px;
font-weight: 700;
text-shadow: rgba(0, 0, 0, 0.5) 0 10px 10px;
}3. Activate the parallax cards. Place the following JS snippets after you load the latest Vue.js library.
Vue.config.devtools = true;
Vue.component("card", {
template: `
<div class="card-wrap"
@mousemove="handleMouseMove"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
ref="card">
<div class="card"
:style="cardStyle">
<div class="card-bg" :style="[cardBgTransform, cardBgImage]"></div>
<div class="card-info">
<slot name="header"></slot>
<slot name="content"></slot>
</div>
</div>
</div>`,
mounted() {
this.width = this.$refs.card.offsetWidth;
this.height = this.$refs.card.offsetHeight;
},
props: ["dataImage"],
data: () => ({
width: 0,
height: 0,
mouseX: 0,
mouseY: 0,
mouseLeaveDelay: null }),
computed: {
mousePX() {
return this.mouseX / this.width;
},
mousePY() {
return this.mouseY / this.height;
},
cardStyle() {
const rX = this.mousePX * 30;
const rY = this.mousePY * -30;
return {
transform: `rotateY(${rX}deg) rotateX(${rY}deg)` };
},
cardBgTransform() {
const tX = this.mousePX * -40;
const tY = this.mousePY * -40;
return {
transform: `translateX(${tX}px) translateY(${tY}px)` };
},
cardBgImage() {
return {
backgroundImage: `url(${this.dataImage})` };
} },
methods: {
handleMouseMove(e) {
this.mouseX = e.pageX - this.$refs.card.offsetLeft - this.width / 2;
this.mouseY = e.pageY - this.$refs.card.offsetTop - this.height / 2;
},
handleMouseEnter() {
clearTimeout(this.mouseLeaveDelay);
},
handleMouseLeave() {
this.mouseLeaveDelay = setTimeout(() => {
this.mouseX = 0;
this.mouseY = 0;
}, 1000);
} } });
const app = new Vue({
el: "#app"
});Preview:





