skip to Main Content

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 and height: 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 using GSAP. 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):

enter image description here

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


  1. 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.

    :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 */
        :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;
          transform: translateY(75px);
          max-height: 400px;
          transition: max-height 1.5s ease-in;
        }
        .hoverCard__header {
          height: 350px;
          background-color: var(--yellow);
        }
        .hoverCard__showOnHover {
          max-height: 0;
          width: 80%;
          transition: max-height 1s ease-out;
          overflow: hidden;
        }
        .hoverCard__body {
          width: 100%;
          padding: 30px 30px 40px 30px;
        }
    <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>
    Login or Signup to reply.
  2. The trick is to set the text to show to max-height: 0 and overflow: hidden. Here is a minimal reproducible example.

    body {
      margin: 1rem;
      font-family: system-ui, sans-serif;
    }
    
    .item {
      position: relative;
      overflow: hidden;
      margin-right: 0.8rem;
      width: 150px;
      float: left;
      border: 1px solid #777;
      border-radius: 3px;
    }
    
    .item.first {
      background: url("https://upload.wikimedia.org/wikipedia/commons/d/d0/Queen_Clementia_of_Hungary.jpg") no-repeat top left;
      background-size: cover;
      height: 150px;
    }
    
    .collapsible {
      height: inherit;
      width: inherit;
      position: absolute;
      bottom: 0;
    }
    
    .collapsible .header {
      background-color: #EEE;
      color: #000;
      text-align: center;
      font-weight: bold;
      font-size: 0.9rem;
      cursor: pointer;
      bottom: 0;
      width: 100%;
      position: absolute;
      opacity: 0.8;
    }
    
    .item .collapsible .collapsibleTxt {
      max-height: 0;
      text-align: left;
      font-size: initial;
      color: #444;
      overflow: hidden;
      padding: 4px;
      font-weight: normal;
      transition: max-height 0.5s ease-in-out;
    }
    
    .header:hover  .collapsibleTxt {
      overflow: initial;
      height: auto;
      max-height: 100px;
    }
    <div class="item first">
      <div class="collapsible">
        <div class="header">Who's that?
          <div class="collapsibleTxt">
            It's Clementia of Hungary!<br>
            <a target="_blank" 
               href="https://en.wikipedia.org/wiki/Clementia_of_Hungary"
            >Find out more</a>
          </div>
        </div>
      </div>
    </div>
    Login or Signup to reply.
  3. So, the following is my solution/workaround. I’ve set the .hoverCard__body to absolute position and gave it a bottom: 0;. And since there’s a missing "blackness", I gave a linear-gradient to .hoverCard__body to compensate the loss.

    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;
    }
    
    
    /*new code*/
    
    .hoverCard__body {
      position: absolute;
      bottom: 0;
      background-color: var(--black);
    }
    
    .hoverCard__header {
      background-image: linear-gradient(var(--yellow) 70%, var(--black) 30%);
    }
    <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>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search