Cards mouse hover effect with CSS + JS

yxsh

Yash

Posted on February 27, 2023

Cards mouse hover effect with CSS + JS

In this blog post we will recreate windows 10 start menu's button hover effects,

you can try the final result on codepen -

1. Create a card with basic stylings.

First of all you need a basic card with some stylings -

<div class="card">
  <h1>Hi dev.to!</h1>
  <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo ut</p>
</div>
Enter fullscreen mode Exit fullscreen mode
.card {
  border-radius: 10px;
  padding: 20px;
  width: 210px;
  height: 150px;
  background: rgb(26,26,26);
}
Enter fullscreen mode Exit fullscreen mode

and I am also gonna add some styling to <body> to position the card in the center, add a better font and change background & text color -

body {
  margin: 0;
  background: black;
  font-family: Verdana, sans-serif;
  color: white;
  display: inline-flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  align-content: center;
  min-height: 100vh;
  width: 100%;
  gap: 8px;
  flex-wrap: wrap;
}
Enter fullscreen mode Exit fullscreen mode

Now the page should like this -

basic card style

2. Creating a border

Now we need to create a border which will glow when the mouse comes near it.

But we cant just use css border property for this. Imagine if that property didn't existed? How would you make a border then.

You would add the element inside a <div> with a background.

so we will rename the .card class to .inner and create a new class .card -

.card {
  background: red; /* border color */
  padding : 3px; /* border width */
  border-radius: 12px;
}
Enter fullscreen mode Exit fullscreen mode

and wrap it around the card -

<div class="card">
  <div class="inner">
    <h1>Hi dev.to!</h1>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo ut</p>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

And now you have a border -

Image description

we are going to keep the border color red for now.

3. Adding Light & Glow Effect

Now we we will create a new element and give it a class .blob -

<div class="card">
  <div class="inner">
    <h1>Hi dev.to!</h1>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo ut</p>
  </div>
  <div class="blob"></div>
</div>
Enter fullscreen mode Exit fullscreen mode

and the element will be positioned absolute -

.blob {
  filter: blur(40px);
  position: absolute;
  z-index: -1; /* to keep it at below everything else */
  top: 0; /* to align it at top */
  left: 0; /* to align it at left */
  width: 250px;
  height: 250px;
  border-radius: 50%; /* to make it circular */
  background: rgb(255, 255, 255, 0.5);
}
Enter fullscreen mode Exit fullscreen mode

Now the blob should appear on top-left of the window -

but we wanted it to be on the top-left of the card.

The reason it went on the top-left of the window is because the absolute positioned element needs a non-static position element to position themselves along.

Since it didn't find any non-static elements it position itself along the <body>.

so to fix it add a position: relative; to the .card class -

.card {
  background: red;
  padding : 3px;
  border-radius: 12px;
  position: relative;
}
Enter fullscreen mode Exit fullscreen mode

Now it should position itself along the .card.

Image description

But now the the glow is escaping out of the card, which we don't want.

You might think, we also want other cards near it to glow. But we only want the border of surroundings to glow, and now the card is just spreading the light everywhere. Instead every card will have their own light which will go towards the mouse and glow their borders.

So, we will add overflow: hidden; to .card class to stop it from spreading out, and we will also change the border color to
background: rgb(128 128 128 / 0.2);, so that we can actually see the glow

.card {
  background: rgb(128 128 128 / 0.2);
  padding : 3px;
  border-radius: 12px;
  position: relative;
  overflow: hidden;
}
Enter fullscreen mode Exit fullscreen mode

Now you should be able to see the glow -

Image description

4. Making the blob follow the mouse.

Now we will start writing some javascript!

first of all you need another element with a class .fakeblob -

<div class="card">
  <div class="inner">
    <h1>Hi dev.to!</h1>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo ut</p>
  </div>
  <div class="blob"></div>
  <div class="fakeblob"></div>
</div>
Enter fullscreen mode Exit fullscreen mode
.fakeblob {
  display: hidden;
  position: absolute;
  z-index: -1;
  top: 0;
  left: 0;
  width: 200px;
  height: 200px;
  border-radius: 50%;
}
Enter fullscreen mode Exit fullscreen mode

we just need this because we need the original position of the blob, and thats why its display: hidden;.

But why can't we save the original in a JS variable, and use it later on? We can't because the blob's original position might change like on scroll and zoom in/out, so we used a fakeblob.

Now the Javascript part!

First of all we will fetch all our card elements and save it in a variable -

const allCards = document.querySelectorAll(".card");
Enter fullscreen mode Exit fullscreen mode

Then we will add add an eventListener, which will listen to mouse movement, inside it we will loop through all of the cards and fetch its .blob and .fakeblob childrens -

window.addEventListener("mousemove", (ev) => {

  allCards.forEach((e) => {
    const blob = e.querySelector(".blob");
    const fblob = e.querySelector(".fakeblob");
  });
});
Enter fullscreen mode Exit fullscreen mode

then we will getBoundingClientRect() of the fakeblob which will return an object providing information about the size of an element and its position relative to the viewport -

allCards.forEach((e) => {
  const blob = e.querySelector(".blob");
  const fblob = e.querySelector(".fakeblob");

  const rec = fblob.getBoundingClientRect();
});
Enter fullscreen mode Exit fullscreen mode

now we will animate the blob using the web animation api -

blob.animate(
  [{
      transform: `translate(${ev.clientX - rec.left - (rec.width / 2)}px,${ev.clientY - rec.top - (rec.height / 2)}px)`,
  }],
  {
    duration: 300,
    fill: "forwards",
  }
);
Enter fullscreen mode Exit fullscreen mode

here we are animating it for the duration - 300ms and fill - forwards means that the element will keep the styles of the last keyframe.

and in the animation we are translating it by the difference between mouse position and fake blob position.

And we also subtracting it by half of its height in y axis and half of width in x axis. The reason for this is to make the blob move to the center of the mouse.

without it the blob would move like this -

and with it it would move like this -

Now try moving your mouse near the card -

add few more cards and see the magic!

5. Additional effects

Now when you hover the cards it does nothing & its kinda boring so lets add a glow effect following the mouse -

first we will add a transition property to smoothly transition into the :hover state

.inner {
  /* ... */
  transition: background 300ms ease-in-out;
}
Enter fullscreen mode Exit fullscreen mode

and on .card:hover we will change the background opacity and add a backdrop blur -

.card:hover > .inner {
  background: rgb(26, 26, 26, 0.6);
  backdrop-filter: blur(80px);
}
Enter fullscreen mode Exit fullscreen mode

and now -

And there you have it!

Thanks for reading the blog! I hope it helped you :)

💖 💪 🙅 🚩
yxsh
Yash

Posted on February 27, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related