Cool Button Hover Effect: A Step By Step Tutorial using HTML, CSS and JavaScript

Cool Button Hover Effect: A Step By Step Tutorial using HTML, CSS and JavaScript

Learn how to make a hover effect that fills a button with color from bottom to top on hover, and fills out from bottom to top on hover out

Behind The Scenes Preview

To help you understand how this hover effect really works, here's what it looks like behind the scenes:

Starting HTML Structure

<button class="btn">
  Hover me
</button>

CSS Styles

body{
  background: #111;
}

.btn {
  background-color: #212529;
  color: white;
  cursor:pointer;
  font-size: 1.5rem;
  padding: 2rem 4rem;
  border: none;
  border-radius: 100vmax;
  position: relative;
  transition: scale 0.4s ease;
}

Creating the Button Fill Element

Now we'll create a new element inside the button that we will use to fill the button when we hover over it:

<button class="btn">
  <div class="btn-fill"></div>
  Hover me
</button>
.btn-fill {
  background: #228be6;
  width: 150%;
  height: 200%;
  border-radius: 60%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, 50%);
}

Since the default behavior of the CSS :hover selector causes the element to go back to its normal position when we hover out, and we want the fill element to move upwards instead of returning downwards when hovered out, we will need to use JavaScript to handle the transitions.

Animating the Button Fill

First, let's create a reusable function for animating the button fill element.

function animateBtnFill(btnFill, translateY, duration) {
  requestAnimationFrame(() => {
    btnFill.animate(
      {
        transform: `translate(-50%, ${translateY}%)`,
      },
      { duration, fill: 'forwards', easing: 'ease' }
    )
  })
}

By placing the animate method inside the requestAnimationFrame, the animation is synchronized with the browser's rendering, leading to a smoother and more visually appealing animation.

We used animate method to set the position of the btn-fill and set the fill option to forwards so the btn-fill won't go back to its original position when the animation is done.

Setting up mouse enter/leave event:

const buttons = document.querySelectorAll('.btn');

buttons.forEach((btn) => {
  const btnFill = btn.querySelector('.btn-fill')

  btn.addEventListener('mouseenter', () => {
    // Mouse Enter Event
  });

  btn.addEventListener('mouseleave', () => {
    // Mouse Leave Event
  });
});

In the code snippet above we used querySelectorAll to select all the buttons in the DOM and loop through all the buttons where we attach event listeners for mouse enter/leave, we did this so that we can use this hover effect in multiple buttons.

Let's animate the btn-fill on mouseenter:

btn.addEventListener('mouseenter', () => {
  animateBtnFill(btnFill, 50, 0);

  animateBtnFill(btnFill, -50, 850);
});

In the code snippet above we used animateBtnFill(btnFill, 50, 0) to set the Y position of the btn-fill to 50% and 0 duration on mouseenter so it just flicks back to the bottom when we hover the button therefore it will always come from the bottom when we hover the button.

After that, the second animation happens animateBtnFill(btnFill, -50, 850), it sets the btn-fill Y to -50% which puts it in the center of the button which makes it look like the button is being filled with its color.

Now let's animate the btn-fill to go above the bottom on mouseleave :

btn.addEventListener('mouseleave', () => {
  animateBtnFill(btnFill, -150, 850)
})

Setting Button Overflow to Hidden

.btn {
 overflow: hidden;
}

Fixing z-index Issue

Great, now we just need to fix the issue of the btn-fill covering the content of our button:

<button class="btn">
  <div class="btn-fill"></div>
  <div class="btn-content">Hover me</div>
</button>
.btn-content {
  position:relative;
  z-index: 2;
}

We have created a div called btn-content that will contain the contents of our button. We have also set its position to relative so that the z-index applies to the btn-content and places it on top of the btn-fill.

Changing the Button Scale on Hover

Finally let's just change the scale of the button when we hover over it:

.btn:hover {
  scale: 1.05;
}

External Links:
Codepen Link: link
Learn more about requestAnimationFrame and animate

That's it you just learned how to achieve this cool hover effect, I hope you found this one helpful and If you have any questions or comments please feel free to leave them in the comments section.