skip to Main Content

I’m trying to make the button that shows icon after hovering.

Now, the button seems to be stuck in hover when you stay ~2sec in hover state

Can anyone fix this? And try to make it smoother?

GIF: bro

.button {
  width: fit-content;
  height: fit-content;
  padding: 10px 15px;
  background-color: #323232;
  color: white;
  border-radius: 10px;
  align-items: center;
  justify-content: center;
  display: flex;
  cursor: pointer;
  position: relative;
  border: 1px solid #bdc3c7;
}

.button-text-container {
  order: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  overflow: hidden;
  width: 0;
  transition-duration: 1s;
  transition-property: max-width;
  transition-timing-function: ease-in-out;
  font-size: 1.5em;
  width: fit-content;
  max-width: 0;
}

.button-icon-container {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
  font-size: 1.6em;
}

.button:hover .button-text-container {
  max-width: 1275px;
}

.button-text-container>span {
  margin: 10px;
}
<div class="button">
  <div class="button-icon-container">icon</div>
  <div class="button-text-container"><span>test</span></div>
</div>

2

Answers


  1. The problem is with this line:

    max-width: 1275px;
    

    Basically, what happens during transitions is based on the set duration (in your case, 1s), the transition property value keeps changing. So in your case, max-width gets changed from 0 to 1275 over 1s period.

    If the transition ends prematurely, that is, if you move your mouse out before 1s, the reverse transition happens, that is, max-width starts decreasing from whatever value at that point (say, 700) to 0 over the exact same duration that changed it from 0 to 700. It will be less than 1s because you ended it prematurely.

    And because in your code, the visual change is only visible for the initial brief duration, you think you experience that the more you have your mouse inside the element, the more "delay" you get.

    You can visualize what’s happening to max-width by changing your transition property from max-width to width.

    .button {
      width: fit-content;
      height: fit-content;
      padding: 10px 15px;
      background-color: #323232;
      color: white;
      border-radius: 10px;
      align-items: center;
      justify-content: center;
      display: flex;
      cursor: pointer;
      position: relative;
      border: 1px solid #bdc3c7;
    }
    
    .button-text-container {
      order: 1;
      display: flex;
      align-items: center;
      justify-content: center;
      white-space: nowrap;
      overflow: hidden;
      width: 0;
      transition-duration: 1s;
      transition-property: width;
      transition-timing-function: ease-in-out;
      font-size: 1.5em;
      width: fit-content;
      width: 0;
    }
    
    .button-icon-container {
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 10px;
      font-size: 1.6em;
    }
    
    .button:hover .button-text-container {
      width: 1275px;
    }
    
    .button-text-container>span {
      margin: 10px;
    }
    <div class="button">
      <div class="button-icon-container">icon</div>
      <div class="button-text-container"><span>test</span></div>
    </div>

    So, the solution is to not transition max-width (I don’t know why you used it) and use magic numbers but instead, use a better solution like this.

    Login or Signup to reply.
  2. The problem in animating to max-width/height: "big-magic-number"unit; lies exactly in the number being magic and big. Takes time to revert to 0 during a defined transition period.

    Transitioning a carousel using max-width / max-height is flawed and broken by design.

    Animate width to "auto" solution:

    A better solution would be using CSS grid as explained in this answer, where basically the animation transitions from 0fr to 1fr

    .button {
      display: inline-flex;
      align-items: center;
      padding: 10px 15px;
      background-color: #323232;
      color: white;
      border-radius: 10px;
      cursor: pointer;
      border: 1px solid #bdc3c7;
    }
    
    .button-slide {
      display: grid;
      grid-template-columns: 0fr;
      transition: grid-template-columns 0.4s ease-in-out;
    }
    
    .button:hover .button-slide {
      grid-template-columns: 1fr;
    }
    
    .button-slide-inner {
      overflow: hidden;
    }
    <div class="button">
      <span class="button-icon">❤️</span>
      <div class="button-slide">
        <div class="button-slide-inner"><span>Heart</span></div>
      </div>
    </div>

    To recap, use grid-template-columns to animate "width", and grid-template-rows to animate "height".

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search