I have a block which contains content that appears on hover. The way the effect should work is:
.hoverCard
shows base content by default (content in .hoverCard__showOnHover is hidden)
User hovers over .hoverCard at which point.hoverCard__showOnHover
reveals its contents and the.hoverCard__body
translates up (giving it that "open" effect)- A visual of the above can be seen in my demo, but I cannot get the animation to work neatly.
The issue(s) I’m running into are:
- using
visibility: hidden
,opacity: 0
andheight: 0
still reserves space for.hoverCard__showOnHover
. Meaning that if by default,.hoverCard__body
has 40px padding at the bottom, and.hoverCard__showOnHover
is 100px in height, 140px space can be seen on .hoverCard without the user hovering - The only way I know can prevent the reservation of space is by using display: none. However, when I hover over the card, I need to give it a display property to showcase the content, which gives the card a jumping effect (as the height is being introduced on hover). In addition to this, my card also grows in height (I want the effect of content being revealed and opening upwards, rather than growing .hoverCard as it does in the demo)
- To try resolve the above, I’ve tried giving
.hoverCard__showOnHover
height gradually by usingGSAP
. But no luck, as it still presents the above issues
Is there a way I can tackle this? It doesn’t have to be using GSAP, I’ve just tried GSAP in an attempt to resolve the above issues.
const hoverCard = document.querySelector('.hoverCard');
const hoverCardBodyShowOnHover = document.querySelector('.hoverCard__showOnHover');
hoverCard.addEventListener('mouseenter', function() {
gsap.to(hoverCardBodyShowOnHover, { duration: 0.5, display: 'block', height: 'auto', ease: 'power4.out' });
});
hoverCard.addEventListener('mouseleave', function() {
gsap.to(hoverCardBodyShowOnHover, { duration: 0.5, height: 0, ease: 'power4.out', onComplete: function() {
this.targets()[0].style.display = 'none';
}});
});
:root {
--black: #000000;
--white: #ffffff;
--yellow: #FFE775;
}
/* general */
body {
font-family: "Poppins", sans-serif;
background-color: var(--white);
color: var(--black);
}
section {
margin: 100px 0 300px 0;
}
/* card */
.hoverCard {
margin-bottom: 15px;
width: 100%;
border-radius: 8px;
overflow: hidden;
background-color: var(--black);
color: var(--white);
border: 1px solid var(--black);
}
.hoverCard * {
transition: all 0.5s ease;
}
.hoverCard:hover .hoverCard__body {
transform: translateY(-75px);
}
.hoverCard:hover .hoverCard__body .hoverCard__showOnHover {
opacity: 1;
visibility: visible;
display: block;
height: auto;
transform: translateY(75px);
}
.hoverCard__header {
height: 350px;
background-color: var(--yellow);
}
.hoverCard__showOnHover {
display: none;
height: 0;
overflow: hidden;
}
.hoverCard__body {
width: 100%;
padding: 30px 30px 40px 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.3/gsap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css" rel="stylesheet">
<section>
<div class="container">
<div class="row">
<div class="col-12 col-md-6">
<article class="hoverCard position-relative">
<div class="hoverCard__header">
<!-- img here -->
</div>
<div class="hoverCard__body">
<div class="hoverCard__body-text">Subheader</div>
<div class="hoverCard__showOnHover">
<p>This will show on hover Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
</div>
</article>
</div>
<div class="col-12 col-md-6">
<article class="hoverCard position-relative">
<div class="hoverCard__header">
<!-- img here -->
</div>
<div class="hoverCard__body">
<div class="hoverCard__body-text">Subheader 2</div>
<div class="hoverCard__showOnHover">
<p>This will show on hover</p>
</div>
</div>
</article>
</div>
</div>
</div>
</section>
Here is a visual of the default version of the card (see right card) and how the hover interaction works (left card):
Notice how the card height doesn’t increase. Instead, the body moves up (within the card) to reveal the content.
Edit:
Based on Kooilnc’s answer:
:root {
--black: #000000;
--white: #ffffff;
--yellow: #FFE775;
}
/* general */
body {
background-color: var(--white);
color: var(--black);
}
section {
margin: 100px 0 300px 0;
}
/* card */
.hoverCard {
margin-bottom: 15px;
width: 100%;
border-radius: 8px;
overflow: hidden;
background-color: var(--black);
color: var(--white);
border: 1px solid var(--black);
position: relative; /* added */
}
.hoverCard * {
transition: all 0.5s ease;
}
.hoverCard:hover .hoverCard__body {
transform: translateY(-75px);
}
.hoverCard:hover .hoverCard__body .hoverCard__showOnHover {
/* opacity: 1;
visibility: visible;
display: block;
height: */ auto;
overflow: initial; /* added */
height: auto; /* added */
max-height: 100px; /* added */
transform: translateY(75px);
}
.hoverCard__header {
height: 200px;
background-color: var(--yellow);
}
.hoverCard__showOnHover {
overflow: hidden;
max-height: 0; /* added */
transition: max-height 0.5s ease-in-out; /* added */
overflow: hidden; /* added */
}
.hoverCard__body {
width: 100%;
padding: 30px 30px 40px 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.3/gsap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css" rel="stylesheet">
<section>
<div class="container">
<div class="row">
<div class="col-6">
<article class="hoverCard position-relative">
<div class="hoverCard__header">
<!-- img here -->
</div>
<div class="hoverCard__body">
<div class="hoverCard__body-text">Subheader</div>
<div class="hoverCard__showOnHover">
<p>This will show on hover Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
</div>
</article>
</div>
<div class="col-6">
<article class="hoverCard position-relative">
<div class="hoverCard__header">
<!-- img here -->
</div>
<div class="hoverCard__body">
<div class="hoverCard__body-text">Subheader 2</div>
<div class="hoverCard__showOnHover">
<p>This will show on hover</p>
</div>
</div>
</article>
</div>
</div>
</div>
</section>
Also, what do we need to define a number for max-height: 100px;
? What if the content size is unknown and needs to be dynamic?
3
Answers
I guess what you want is to transition in height, and you tried it in CSS but doesn’t work.
My answer is as follows:
when transitioning the height, use
max-height
but not height.The trick is to set the text to show to
max-height: 0
andoverflow: hidden
. Here is a minimal reproducible example.So, the following is my solution/workaround. I’ve set the
.hoverCard__body
toabsolute
position and gave it abottom: 0;
. And since there’s a missing "blackness", I gave alinear-gradient
to.hoverCard__body
to compensate the loss.