Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Hover card
<a href="#" class="card">
<div class="card__head">
<div class="card__image"></div>
<div class="card__author">
<div class="author">
<img src="https://s.gravatar.com/avatar/7ff9e93ff25e002bc49f4d69c0c3eac7?s=80" alt="Author of Tobias Reich" class="author__image">
<div class="author__content">
<p class="author__header">Tobias Reich</p>
<p class="author__subheader">Web developer and designer</p>
</div>
</div>
</div>
</div>
<div class="card__body">
<h2 class="card__headline">Hover me</h2>
<p class="card__text">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore.</p>
</div>
<div class="card__foot">
<span class="card__link">Read more</span>
</div>
<div class="card__border"></div>
</a>
const height = (elem) => {
return elem.getBoundingClientRect().height
}
const distance = (elemA, elemB, prop) => {
const sizeA = elemA.getBoundingClientRect()[prop]
const sizeB = elemB.getBoundingClientRect()[prop]
return sizeB - sizeA
}
const factor = (elemA, elemB, prop) => {
const sizeA = elemA.getBoundingClientRect()[prop]
const sizeB = elemB.getBoundingClientRect()[prop]
return sizeB / sizeA
}
document.querySelectorAll('.card').forEach((elem) => {
const head = elem.querySelector('.card__head')
const image = elem.querySelector('.card__image')
const author = elem.querySelector('.card__author')
const body = elem.querySelector('.card__body')
const foot = elem.querySelector('.card__foot')
elem.onmouseenter = () => {
elem.classList.add('hover')
const imageScale = 1 + factor(head, body, 'height')
image.style.transform = `scale(${ imageScale })`
const bodyDistance = height(foot) * -1
body.style.transform = `translateY(${ bodyDistance }px)`
const authorDistance = distance(head, author, 'height')
author.style.transform = `translateY(${ authorDistance }px)`
}
elem.onmouseleave = () => {
elem.classList.remove('hover')
image.style.transform = `none`
body.style.transform = `none`
author.style.transform = `none`
}
})
body {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 100vh;
font-family: 'Open Sans', sans-serif;
color: #333;
background: #f8f8f8;
}
.card {
$delay: .15s;
$duration: .4s;
$timing: cubic-bezier(.51, .92, .24, 1);
position: relative;
display: flex;
flex-direction: column;
width: 500px;
background: white;
color: currentColor;
text-decoration: none;
overflow: hidden;
transition-property: color;
transition-delay: $delay;
box-shadow: 0 2px 20px rgba(0, 0, 0, .1);
&.hover {
color: white;
transition-delay: 0;
}
&,
&__image,
&__image::after,
&__author,
&__body,
&__foot,
&__border {
transition-duration: $duration;
transition-timing-function: $timing;
}
&__head {
position: relative;
padding-top: 70%;
}
&__author {
position: absolute;
padding: 2em;
left: 0;
bottom: 0;
color: white;
transition-property: transform;
transition-delay: $delay;
}
&.hover &__author {
transition-delay: 0;
}
&__image {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-size: cover;
background-position: center;
background-image: url('https://images.unsplash.com/photo-1553787762-b5f5721f3270?ixlib=rb-1.2.1&auto=format&fit=crop&w=2100&q=80');
transform-origin: top center;
transition-property: transform;
transition-delay: $delay;
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: .5;
background: linear-gradient(30deg, rgba(#1a2a63, .85), rgba(#1a2a63, .5));
transition-property: opacity;
transition-delay: $delay;
}
}
&.hover &__image {
transition-delay: 0;
&::after {
opacity: 1;
transition-delay: 0;
}
}
&__body {
position: relative;
padding: 2em;
transition-property: transform;
transition-delay: $delay;
}
&.hover &__body {
transition-delay: 0;
}
&__headline {
font-weight: 400;
margin: 0 0 .8em;
}
&__text {
line-height: 1.5;
margin: 0;
opacity: .8;
}
&__foot {
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 0 2em 2em;
opacity: 0;
transition-property: opacity;
}
&.hover &__foot {
opacity: 1;
transition-delay: $delay;
}
&__link {
color: currentColor;
text-decoration: none;
border-bottom: 2px solid #b5272d;
}
&__border {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 6px;
background: #b5272d;
transform: scaleY(0);
transition-property: transform;
}
&.hover &__border {
transform: none;
transition-delay: $delay;
}
}
.author {
display: flex;
align-items: center;
&__image {
$size: 56px;
flex-shrink: 0;
margin-right: 1em;
width: $size;
height: $size;
border-radius: 100%;
overflow: hidden;
}
&__content {
display: grid;
grid-gap: .4em;
font-size: .9em;
}
&__header {
margin: 0;
font-weight: 600;
}
&__subheader {
margin: 0;
opacity: .8;
}
}
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.