Headers

Bubble button with following arrow

31 Oct 2023

HTML
SCSS
PostCSS
JS
                            <a 
  href="#"
  class="bubble-btn"
>
  <span class="bubble-btn__text">
    More about us
  </span>
  <span class="bubble-btn__arrow-wrap">
    <div class="bubble-btn__arrow">
      <svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 448 512">
        <path d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"/></svg>
		</div>
	</span>
</a>

                        
                            :root{
  --primary-cl: tomato;
  --secondary-cl: blueviolet;
  --white: white;
}

.bubble-btn {
  box-sizing: border-box;
  position: relative;

  display: flex;
  justify-content: center;
  align-items: center;

  width: 200px;
  height: 200px;

  padding: 48px 39px;
  border-radius: 999px;

  background: var(--primary-cl);
  color: var(--white);
  
  font-family: sans-serif;
  font-weight: 700;
  text-decoration: none;

  &:hover {
    .bubble-btn__arrow {
      opacity: 0.5;
      transform: scale(1.4);
    }

    .bubble-btn__arrow.rotate-90 {
      transform: scale(1.4) rotate(90deg);
    }
  }
}

.bubble-btn__text {
  position: relative;
  z-index: 1;
  bottom: 12px;

  font-size: 30px;
  font-weight: 500;
  text-align: center;

  pointer-events: none;
}

.bubble-btn__arrow-wrap {
  position: absolute;
  left: 50%;
  top: calc(100% - 44px);
  transform: translateX(-50%);

  pointer-events: none;
}

.bubble-btn__arrow {
  display: flex;
  justify-content: center;
  align-items: center;

  width: 58px;
  height: 58px;

  border-radius: 999px;

  background: var(--secondary-cl);

  font-size: 17px;

  transition: all ease 250ms;
  
  svg {
    fill: var(--white);
  }
}

                        
                            :root{
  --primary-cl: tomato;
  --secondary-cl: blueviolet;
  --white: white;
}

.bubble-btn {
  box-sizing: border-box;
  position: relative;

  display: flex;
  justify-content: center;
  align-items: center;

  width: 200px;
  height: 200px;

  padding: 48px 39px;
  border-radius: 999px;

  background: var(--primary-cl);
  color: var(--white);
  
  font-family: sans-serif;
  font-weight: 700;
  text-decoration: none;

  &:hover {
    .bubble-btn__arrow {
      opacity: 0.5;
      transform: scale(1.4);
    }

    .bubble-btn__arrow.rotate-90 {
      transform: scale(1.4) rotate(90deg);
    }
  }
}

.bubble-btn__text {
  position: relative;
  z-index: 1;
  bottom: 12px;

  font-size: 30px;
  font-weight: 500;
  text-align: center;

  pointer-events: none;
}

.bubble-btn__arrow-wrap {
  position: absolute;
  left: 50%;
  top: calc(100% - 44px);
  transform: translateX(-50%);

  pointer-events: none;
}

.bubble-btn__arrow {
  display: flex;
  justify-content: center;
  align-items: center;

  width: 58px;
  height: 58px;

  border-radius: 999px;

  background: var(--secondary-cl);

  font-size: 17px;

  transition: all ease 250ms;
  
  svg {
    fill: var(--white);
  }
}

                        
                            const bubbleBtnList = document.querySelectorAll(".bubble-btn");

  if (bubbleBtnList.length) {
    bubbleBtnList.forEach((btn) => {
      const arrowBubble = btn.querySelector(".bubble-btn__arrow-wrap");

      btn.addEventListener(
        "mousemove",

        ({ offsetX, offsetY, target: { offsetWidth, offsetHeight } }) => {
          arrowBubble.style.left = `${offsetX}px`;
          arrowBubble.style.top = `${offsetY}px`;
          arrowBubble.style.transform = `translate(-50%, -50%)`;
        }
      );

      btn.addEventListener("mouseenter", () => {
        arrowBubble.style.transition =
          "width 0.3s ease, top 0.3s ease, left 0.3s ease";

        setTimeout(() => {
          arrowBubble.style.transition = null;
        }, 300);
      });

      btn.addEventListener("mouseleave", () => {
        arrowBubble.style.transition =
          "width 0.3s ease, top 0.3s ease, left 0.3s ease";

        setTimeout(() => {
          arrowBubble.style.left = null;
          arrowBubble.style.transform = null;

          if (!btn.classList.contains("job-card")) {
            arrowBubble.style.top = null;
          } else {
            arrowBubble.style.top = topPos;
          }

          setTimeout(() => {
            arrowBubble.style.transition = null;
          }, 300);
        }, 200);
      });
    });
  }

                        
0