Canyons
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
<div id="app" class="container">
<card data-image="https://images.unsplash.com/photo-1479660656269-197ebb83b540?dpr=2&auto=compress,format&fit=crop&w=1199&h=798&q=80&cs=tinysrgb&crop=">
<h1 slot="header">Canyons</h1>
<p slot="content">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
</card>
</div>
<link href="https://fonts.googleapis.com/css?family=Playfair+Display:700|Raleway:500.700" rel="stylesheet" type="text/css"></link>
<style>
#app {
margin: 40px 0;
font-family: "Raleway";
font-size: 14px;
font-weight: 500;
background-color: #BCAAA4;
-webkit-font-smoothing: antialiased;
}
.title {
font-family: "Raleway";
font-size: 24px;
font-weight: 700;
color: #5D4037;
text-align: center;
}
p {
line-height: 1.5em;
}
h1 + p, p + p {
margin-top: 10px;
}
.container {
padding: 40px 80px;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.card-wrap {
margin: 10px;
transform: perspective(800px);
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: 5s cubic-bezier(0.23, 1, 0.32, 1);
opacity: 1;
transform: translateY(0);
}
.card-wrap:hover .card-bg {
transition: 0.6s cubic-bezier(0.23, 1, 0.32, 1), opacity 5s cubic-bezier(0.23, 1, 0.32, 1);
opacity: 0.8;
}
.card-wrap:hover .card {
transition: 0.6s cubic-bezier(0.23, 1, 0.32, 1), box-shadow 2s cubic-bezier(0.23, 1, 0.32, 1);
box-shadow: rgba(255, 255, 255, 0.2) 0 0 40px 5px, white 0 0 0 1px, rgba(0, 0, 0, 0.66) 0 30px 60px 0, inset #333 0 0 0 5px, inset white 0 0 0 6px;
}
.card {
position: relative;
flex: 0 0 240px;
width: 240px;
height: 320px;
background-color: #333;
overflow: hidden;
border-radius: 10px;
box-shadow: rgba(0, 0, 0, 0.66) 0 30px 60px 0, inset #333 0 0 0 5px, inset rgba(255, 255, 255, 0.5) 0 0 0 6px;
transition: 1s 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: 1s cubic-bezier(0.445, 0.05, 0.55, 0.95), opacity 5s 1s 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: "Playfair Display";
font-size: 36px;
font-weight: 700;
text-shadow: rgba(0, 0, 0, 0.5) 0 10px 10px;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.1/vue.min.js" type="text/javascript"></script>
<script>
'use strict';
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: function mounted() {
this.width = this.$refs.card.offsetWidth;
this.height = this.$refs.card.offsetHeight;
},
props: ['dataImage'],
data: function data() {
return {
width: 0,
height: 0,
mouseX: 0,
mouseY: 0,
mouseLeaveDelay: null
};
},
computed: {
mousePX: function mousePX() {
return this.mouseX / this.width;
},
mousePY: function mousePY() {
return this.mouseY / this.height;
},
cardStyle: function cardStyle() {
var rX = this.mousePX * 30;
var rY = this.mousePY * -30;
return {
transform: 'rotateY(' + rX + 'deg) rotateX(' + rY + 'deg)'
};
},
cardBgTransform: function cardBgTransform() {
var tX = this.mousePX * -40;
var tY = this.mousePY * -40;
return {
transform: 'translateX(' + tX + 'px) translateY(' + tY + 'px)'
};
},
cardBgImage: function cardBgImage() {
return {
backgroundImage: 'url(' + this.dataImage + ')'
};
}
},
methods: {
handleMouseMove: function 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: function handleMouseEnter() {
clearTimeout(this.mouseLeaveDelay);
},
handleMouseLeave: function handleMouseLeave() {
var _this = this;
this.mouseLeaveDelay = setTimeout(function () {
_this.mouseX = 0;
_this.mouseY = 0;
}, 1000);
}
}
});
var app = new Vue({
el: '#app'
});
</script>
<card data-image="https://images.unsplash.com/photo-1479660656269-197ebb83b540?dpr=2&auto=compress,format&fit=crop&w=1199&h=798&q=80&cs=tinysrgb&crop=">
<h1 slot="header">Canyons</h1>
<p slot="content">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
</card>
</div>
<link href="https://fonts.googleapis.com/css?family=Playfair+Display:700|Raleway:500.700" rel="stylesheet" type="text/css"></link>
<style>
#app {
margin: 40px 0;
font-family: "Raleway";
font-size: 14px;
font-weight: 500;
background-color: #BCAAA4;
-webkit-font-smoothing: antialiased;
}
.title {
font-family: "Raleway";
font-size: 24px;
font-weight: 700;
color: #5D4037;
text-align: center;
}
p {
line-height: 1.5em;
}
h1 + p, p + p {
margin-top: 10px;
}
.container {
padding: 40px 80px;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.card-wrap {
margin: 10px;
transform: perspective(800px);
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: 5s cubic-bezier(0.23, 1, 0.32, 1);
opacity: 1;
transform: translateY(0);
}
.card-wrap:hover .card-bg {
transition: 0.6s cubic-bezier(0.23, 1, 0.32, 1), opacity 5s cubic-bezier(0.23, 1, 0.32, 1);
opacity: 0.8;
}
.card-wrap:hover .card {
transition: 0.6s cubic-bezier(0.23, 1, 0.32, 1), box-shadow 2s cubic-bezier(0.23, 1, 0.32, 1);
box-shadow: rgba(255, 255, 255, 0.2) 0 0 40px 5px, white 0 0 0 1px, rgba(0, 0, 0, 0.66) 0 30px 60px 0, inset #333 0 0 0 5px, inset white 0 0 0 6px;
}
.card {
position: relative;
flex: 0 0 240px;
width: 240px;
height: 320px;
background-color: #333;
overflow: hidden;
border-radius: 10px;
box-shadow: rgba(0, 0, 0, 0.66) 0 30px 60px 0, inset #333 0 0 0 5px, inset rgba(255, 255, 255, 0.5) 0 0 0 6px;
transition: 1s 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: 1s cubic-bezier(0.445, 0.05, 0.55, 0.95), opacity 5s 1s 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: "Playfair Display";
font-size: 36px;
font-weight: 700;
text-shadow: rgba(0, 0, 0, 0.5) 0 10px 10px;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.1/vue.min.js" type="text/javascript"></script>
<script>
'use strict';
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: function mounted() {
this.width = this.$refs.card.offsetWidth;
this.height = this.$refs.card.offsetHeight;
},
props: ['dataImage'],
data: function data() {
return {
width: 0,
height: 0,
mouseX: 0,
mouseY: 0,
mouseLeaveDelay: null
};
},
computed: {
mousePX: function mousePX() {
return this.mouseX / this.width;
},
mousePY: function mousePY() {
return this.mouseY / this.height;
},
cardStyle: function cardStyle() {
var rX = this.mousePX * 30;
var rY = this.mousePY * -30;
return {
transform: 'rotateY(' + rX + 'deg) rotateX(' + rY + 'deg)'
};
},
cardBgTransform: function cardBgTransform() {
var tX = this.mousePX * -40;
var tY = this.mousePY * -40;
return {
transform: 'translateX(' + tX + 'px) translateY(' + tY + 'px)'
};
},
cardBgImage: function cardBgImage() {
return {
backgroundImage: 'url(' + this.dataImage + ')'
};
}
},
methods: {
handleMouseMove: function 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: function handleMouseEnter() {
clearTimeout(this.mouseLeaveDelay);
},
handleMouseLeave: function handleMouseLeave() {
var _this = this;
this.mouseLeaveDelay = setTimeout(function () {
_this.mouseX = 0;
_this.mouseY = 0;
}, 1000);
}
}
});
var app = new Vue({
el: '#app'
});
</script>