0

I made a text animation in JavaScript (JS) where the word that is hovered over changes color letter by letter over time. I only want the text animation to reset when the word isn't being hovered over anymore.

However, when I am hovering over the word and I move my cursor over a different letter in the word the hovering animation resets. Can someone explain why it does this and how I may be able to fix this?

const home = document.querySelector("#home");
const homeText = home.textContent;
const splitHomeText = homeText.split("");

home.textContent = "";
for (let i = 0; i < splitHomeText.length; i++) {
  home.innerHTML += "<span>" + splitHomeText[i] + "</span>";
}

let char = 0;
let timer = null;
home.addEventListener("mouseover", highlight);
home.addEventListener("mouseout", clear);

function highlight() {
  timer = setInterval(onTickHome, 50);
}

function onTickHome() {
  const span = home.querySelectorAll("span")[char];
  span.classList.add("highlight");
  char++;
  if (char === splitHomeText.length) {
    complete();
    return;
  }
}

function complete() {
  char = 0;
  clearInterval(timer);
}

function clear() {
  char = 0;
  clearInterval(timer);
  for (let i = 0; i < splitHomeText.length; i++) {
    const span = home.querySelectorAll("span")[i];
    span.classList.remove("highlight");
  }
}
#home {
  text-decoration: none;
  color: black;
  font-size: 30px;
}

.highlight {
  color: #EF233C;
}
<a href="#" id="home">Home</a>
Daweed
  • 1,419
  • 1
  • 9
  • 24
Sean
  • 3
  • 2

3 Answers3

0

refer this answer for more

const home = document.querySelector("#home");
const homeText = home.textContent;
const splitHomeText = homeText.split("");

home.textContent = "";
for(let i = 0; i < splitHomeText.length; i++){
  home.innerHTML += "<span>" + splitHomeText[i] + "</span>";
}

let char = 0;
let timer = null;
home.addEventListener("mouseenter", highlight);
home.addEventListener("mouseleave", clear);

function highlight() {
  timer = setInterval(onTickHome, 50);
}

function onTickHome() {
  const span = home.querySelectorAll("span")[char];
  span.classList.add("highlight");
  char++;
  if(char === splitHomeText.length) {
    complete();
    return;
  }
}

function complete() {
  char = 0;
  clearInterval(timer);
}

function clear() {
  char = 0;
  clearInterval(timer);
  for(let i = 0; i < splitHomeText.length; i++){
    const span = home.querySelectorAll("span")[i];
    span.classList.remove("highlight");
  }
}
#home {
    text-decoration: none;
    color: black;
    font-size: 30px;
}

.highlight {
    color:#EF233C;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>Hover Text Animation</title>
</head>
<body>
    <a href="#" id="home">Home</a>

    <script src="app.js"></script>
</body>
</html>
ashen madusanka
  • 647
  • 1
  • 9
  • 15
0
  • Something more reusable would be not being dependent on IDs.
  • Use CSS transition-delay to time your span coloring (no need for complicated intervals)

const CharAnim = (sel, color = "#0bf") => {

  const anim = (ev, isIn) =>
    ev.currentTarget.querySelectorAll("span").forEach((EL, i) =>
      EL.style.cssText = `
        transition: 0.2s ease ${(isIn ? 30*i : 0)}ms;
        color: ${(isIn ? color : "")};
      `);
      
  document.querySelectorAll(sel).forEach(EL => {
    EL.addEventListener("mouseenter", ev => anim(ev, 1));
    EL.addEventListener("mouseleave", ev => anim(ev, 0));
    EL.innerHTML = EL.textContent.replace(/./g, "<span>$&</span>");
  });

};


CharAnim("a", "#EF233C");
CharAnim(".test1", "#FB0");
CharAnim(".test2"); // Use default color
a {
  text-decoration: none;
  color: #000;
  font-size: 30px;
}
<a href="#">Home</a><br>
<a href="#">Don't use IDs. Programming is not copy/pasting</a>
<div class="test1">Lorem ipsum</div>
<div class="test2">Dolor sit amet</div>
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
-1

The question asks why moving the mouse from a character onto another one causes the highlighting to disappear.

The problem arises because the mouseout event, which is set on the div (the whole word) is fired when the mouse moves away from any of the div's descendants. So clear gets invoked on any movement of the mouse away from a single character.

What we need is something that gets fired when the mouse moves away from the div/word, not from each span element. The event mouseleave gives us what we want. See MDN

mouseleave is fired when the pointer has exited the element and all of its descendants, whereas mouseout is fired when the pointer leaves the element or leaves one of the element's descendants (even if the pointer is still within the element).

So looking for the mouseleave events instead of the mouseout ones solves the premature resetting of the color-change problem.

const home = document.querySelector("#home");
const homeText = home.textContent;
const splitHomeText = homeText.split("");

home.textContent = "";
for(let i = 0; i < splitHomeText.length; i++){
  home.innerHTML += "<span>" + splitHomeText[i] + "</span>";
}

let char = 0;
let timer = null;
home.addEventListener("mouseenter", highlight);
home.addEventListener("mouseleave", clear);

function highlight() {
  timer = setInterval(onTickHome, 50);
}

function onTickHome() {
  const span = home.querySelectorAll("span")[char];
  span.classList.add("highlight");
  char++;
  if(char === splitHomeText.length) {
    complete();
    return;
  }
}

function complete() {
  char = 0;
  clearInterval(timer);
}

function clear() {
  char = 0;
  clearInterval(timer);
  for(let i = 0; i < splitHomeText.length; i++){
    const span = home.querySelectorAll("span")[i];
    span.classList.remove("highlight");
  }
}
#home {
    text-decoration: none;
    color: black;
    font-size: 30px;
}

.highlight {
    color:#EF233C;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>Hover Text Animation</title>
</head>
<body>
    <a href="#" id="home">Home</a>

    <script src="app.js"></script>
</body>
</html>
A Haworth
  • 30,908
  • 4
  • 11
  • 14