After playing the Gwent Closed Beta from CD Projekt Red, I had to try this concept of parallaxed backgrounds and layers in cards. I'm thinking this could be really nice for my next portfolio site.
A Pen by Andy Merskin on CodePen.
| <h1 class="title">Hover over the cards</h1> | |
| <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> | |
| <card data-image="https://images.unsplash.com/photo-1479659929431-4342107adfc1?dpr=2&auto=compress,format&fit=crop&w=1199&h=799&q=80&cs=tinysrgb&crop="> | |
| <h1 slot="header">Beaches</h1> | |
| <p slot="content">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p> | |
| </card> | |
| <card data-image="https://images.unsplash.com/photo-1479644025832-60dabb8be2a1?dpr=2&auto=compress,format&fit=crop&w=1199&h=799&q=80&cs=tinysrgb&crop="> | |
| <h1 slot="header">Trees</h1> | |
| <p slot="content">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p> | |
| </card> | |
| <card data-image="https://images.unsplash.com/photo-1479621051492-5a6f9bd9e51a?dpr=2&auto=compress,format&fit=crop&w=1199&h=811&q=80&cs=tinysrgb&crop="> | |
| <h1 slot="header">Lakes</h1> | |
| <p slot="content">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p> | |
| </card> | |
| </div> |
After playing the Gwent Closed Beta from CD Projekt Red, I had to try this concept of parallaxed backgrounds and layers in cards. I'm thinking this could be really nice for my next portfolio site.
A Pen by Andy Merskin on CodePen.
| 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' | |
| }); |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.1/vue.min.js"></script> |
| $hoverEasing: cubic-bezier(0.23, 1, 0.32, 1); | |
| $returnEasing: cubic-bezier(0.445, 0.05, 0.55, 0.95); | |
| body { | |
| 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; | |
| // background-color: #fff; | |
| &:hover { | |
| .card-info { | |
| transform: translateY(0); | |
| } | |
| .card-info p { | |
| opacity: 1; | |
| } | |
| .card-info, .card-info p { | |
| transition: 0.6s $hoverEasing; | |
| } | |
| .card-info:after { | |
| transition: 5s $hoverEasing; | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| .card-bg { | |
| transition: | |
| 0.6s $hoverEasing, | |
| opacity 5s $hoverEasing; | |
| opacity: 0.8; | |
| } | |
| .card { | |
| transition: | |
| 0.6s $hoverEasing, | |
| box-shadow 2s $hoverEasing; | |
| box-shadow: | |
| rgba(white, 0.2) 0 0 40px 5px, | |
| rgba(white, 1) 0 0 0 1px, | |
| rgba(black, 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(black, 0.66) 0 30px 60px 0, | |
| inset #333 0 0 0 5px, | |
| inset rgba(white, 0.5) 0 0 0 6px; | |
| transition: 1s $returnEasing; | |
| } | |
| .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 $returnEasing, | |
| opacity 5s 1s $returnEasing; | |
| 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); | |
| p { | |
| opacity: 0; | |
| text-shadow: rgba(black, 1) 0 2px 3px; | |
| transition: 0.6s 1.6s cubic-bezier(0.215, 0.61, 0.355, 1); | |
| } | |
| * { | |
| position: relative; | |
| z-index: 1; | |
| } | |
| &:after { | |
| content: ''; | |
| position: absolute; | |
| top: 0; left: 0; | |
| z-index: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-image: linear-gradient(to bottom, transparent 0%, rgba(#000, 0.6) 100%); | |
| background-blend-mode: overlay; | |
| opacity: 0; | |
| transform: translateY(100%); | |
| transition: 5s 1s $returnEasing; | |
| } | |
| } | |
| .card-info h1 { | |
| font-family: "Playfair Display"; | |
| font-size: 36px; | |
| font-weight: 700; | |
| text-shadow: rgba(black, 0.5) 0 10px 10px; | |
| } |
| <link href="https://fonts.googleapis.com/css?family=Playfair+Display:700|Raleway:500.700" rel="stylesheet" /> |