javascripthtmlcssanimationhover

How to create hover animated effect that follows mouse to a limit?


I'm trying to create a hover effect similar to what is used on this web page: https://www.halo-lab.com/

It is used in the "Our Services" section for the play button on the top right corner (scroll down a bit to see it). It looks like it uses JS that changes the inline style values but to a limited perimeter around it. The inline style has it set to 0 initially.

I'm not sure how they achieved the movement. I figured out the animation effect of the color change, but not it moving with your mouse. I have a JS fiddle with the same arrow, but not the movement part: https://jsfiddle.net/84qpbxwn/

I did notice this site uses GSAP. Could it be an effect using their library?

HTML:

<a href="#" class="button-play" style="will-change: transform; transform: translate3d(0rem, 0rem, 0px) scale3d(1, 1, 1) rotateX(0deg) rotateY(0deg) rotateZ(0deg) skew(0deg, 0deg); transform-style: preserve-3d;">
  <div class="button-play__bg"></div>
  <svg aria-hidden="true" role="img" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="100%" height="100%">
      <path d="M13.9 7.35a.7.7 0 0 1 0 1.213l-8.4 4.85a.7.7 0 0 1-1.05-.606v-9.7a.7.7 0 0 1 1.05-.606l8.4 4.85Z"></path>
    </svg>
</a>

CSS:

.button-play{
  background: #02021e;
  color: white;
  display: flex;
  width: 7rem;
  height: 7rem;
  border-radius: 50%;
  align-items: center;
  justify-content: center;
  position: relative;
  transition: color .4s;
  transform: translate(0);
  margin: 70px;
}

.button-play__bg{
  background-color: #3827c7;
    border-radius: 50%;
    width: 100%;
    height: 100%;
    transition: all .3s;
    position: absolute;
    inset: 0%;
    transform: scale(0);
}

.button-play svg{
  width: 1.75rem;
  height: 1.75rem;
  position: relative;
  z-index: 2;
}

.button-play:hover .button-play__bg{
  transform: scale(1)
}

Solution

  • Nice effect! I tried the following and it seems to work. I think you'll have to adjust some things to make it even smoother.

    <a href="#" class="button-play" id="playButton">
      <div class="button-play__bg"></div>
      <svg aria-hidden="true" role="img" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="100%" height="100%">
          <path d="M13.9 7.35a.7.7 0 0 1 0 1.213l-8.4 4.85a.7.7 0 0 1-1.05-.606v-9.7a.7.7 0 0 1 1.05-.606l8.4 4.85Z"></path>
        </svg>
    </a>
    

    I added an event listener that tracks the mouse movement when it hovers over the button. It calculates the mouse position relative to the center of the button and moves the button slightly based on the mouse movement. When the mouse leaves, it resets the button's position.

    const playButton = document.getElementById('playButton');
    
    playButton.addEventListener('mouseenter', (e) => {
      playButton.classList.add('is-moving');
      
      document.addEventListener('mousemove', moveButton);
    });
    
    playButton.addEventListener('mouseleave', () => {
      playButton.classList.remove('is-moving');
      document.removeEventListener('mousemove', moveButton);
      playButton.style.transform = 'translate(0, 0)'; // Reset to original position
    });
    
    function moveButton(e) {
      const buttonRect = playButton.getBoundingClientRect();
      const mouseX = e.clientX;
      const mouseY = e.clientY;
      
      // Bereken de offset tussen muis en knop
      const offsetX = (mouseX - (buttonRect.left + buttonRect.width / 2)) / 10;
      const offsetY = (mouseY - (buttonRect.top + buttonRect.height / 2)) / 10;
      
      // Verplaats de knop op basis van de muisbeweging
      playButton.style.transform = `translate(${offsetX}px, ${offsetY}px)`;
    }
    

    I also added an .is-moving class to ensure the button moves smoothly using transitions.

    .button-play {
      background: #02021e;
      color: white;
      display: flex;
      width: 7rem;
      height: 7rem;
      border-radius: 50%;
      align-items: center;
      justify-content: center;
      position: relative;
      transition: color .4s;
      margin: 70px;
      transform: translate(0);
    }
    
    .button-play__bg {
      background-color: #3827c7;
      border-radius: 50%;
      width: 100%;
      height: 100%;
      transition: all .3s;
      position: absolute;
      inset: 0%;
      transform: scale(0);
    }
    
    .button-play svg {
      width: 1.75rem;
      height: 1.75rem;
      position: relative;
      z-index: 2;
    }
    
    .button-play:hover .button-play__bg {
      transform: scale(1);
    }
    
    .is-moving {
      transition: transform 0.1s ease-out;
    }
    

    There is no need for a library. Here's the jsfiddle: https://jsfiddle.net/q49tgupj/

    Quite a fun effect. Kudos for trying to make it yourself.