Home > Software design >  Cycle through assigned colors on mouseover
Cycle through assigned colors on mouseover

Time:12-03

I have a mouseover (hover) state I’m trying to work out. I have a set of anchors, and I’m wrapping each letter in a span and assigning a color to each from an array. What I’m looking to do is on mouseover, assign a color to each span again repeatedly in a sequence (from the array), like a constantly animating color sequence across each letter of a word.

Updated: Currently the current anchor cycles (with help from Andrew Shearer I ended up targeting the current instead of all anchors), but not each individual cycling to its next color ... it’s working but a bit weird.

A simple visual of what I’m trying to do

My start below:

var colors = [
    "red",
    "lightsalmon",
    "violet",
    "skyblue"];

  $('a').each(function (index) {
    var characters = $(this).text().split("");

    $this = $(this);
    $this.empty();
    $.each(characters, function (i, el) {
      $this.append(`<span style="color: ${colors[i % colors.length]}">${el}</span>`);
    });

  });

  $('a').on('mouseover', function () {
    var span = $(this).find('span');

    intervalId = setInterval(function () {
      color = colors.shift();
      span.each(function (i) {
        $(this).next().attr("style", `color:${colors[i % colors.length]}`);
      });
      colors.push(color);
    }, 500);
  }).on('mouseleave', function () {
    clearInterval(intervalId);
  });

https://jsfiddle.net/34bj70tn/

CodePudding user response:

To achieve the effect you're describing, you could use the setInterval function to repeatedly reassign colors to each span element. Inside the mouseover event handler, you can use setInterval to call a function that updates the colors of each span element at a regular interval. You can then use the clearInterval function to stop the interval when the mouse leaves the a element:

var colors = [
    "red",
    "lightsalmon",
    "violet",
    "skyblue"
];

var intervalId; // Declare a variable to store the interval ID

$('a').each(function (index) {
    var characters = $(this).text().split("");

    $this = $(this);
    $this.empty();
    $.each(characters, function (i, el) {
        $this.append(`<span style="color: ${colors[i % colors.length]}">${el}</span>`);
    });
});

$('a').on('mouseover', function() {
    // Start the interval
    intervalId = setInterval(function() {
        color = colors.shift();
        $('span').each(function() {
            $(this).css('color', color);
        });
        colors.push(color);
    }, 1000); // Update colors every 1 second
}).on('mouseleave', function() {
    // Stop the interval when the mouse leaves the element
    clearInterval(intervalId);
});

CodePudding user response:

A CSS Solution

The rainbow marquee can be created using only css:

  • Wrap each character in a span element
  • Add some css variables to configure the marquee
  • Add a key frame animation for colour sequence
  • Apply the animation to each span using nth-child

Details

We can avoid having to create multiple animations by adding a negative timing delay to each character. This causes the animation to start immediately but at a forward frame. And this way each character stars with different colour.

The animations use step-end timing. This causes the animation to make sharp (rather than gradual) colour transitions like a physical marquee.

The snippet uses a bit of JavaScript on page load to wrap the text characters in spans. However, if you were to add the spans in the markup then no JavaScript is required.

Snippet

// This is called once at to wrap each character in a span to be animated.
// Alternatively, you could add the spans in the markup

document.querySelectorAll('.rainbow')
  .forEach(element => {
    element.innerHTML = element.innerText
      .split('')
      .map(char => `<span>${char}</span>`)
      .join('');
});
/* Set colors and timing via root variables */

:root {
  --rainbow-color-1: red;
  --rainbow-color-2: lightsalmon;
  --rainbow-color-3: violet;
  --rainbow-color-4: skyblue;
  --rainbow-speed: 1;
}

.rainbow span {
  animation: calc(var(--rainbow-speed) * 1s) step-end reverse infinite;
}

.rainbow span:nth-child(4n 1) {
  animation-name: rainbow-animation;
}

.rainbow span:nth-child(4n 2) {
  animation-delay: calc(var(--rainbow-speed) * -0.25s);
  animation-name: rainbow-animation;
}

.rainbow span:nth-child(4n 3) {
  animation-delay: calc(var(--rainbow-speed) * -0.5s);
  animation-name: rainbow-animation;
}

.rainbow span:nth-child(4n 4) {
  animation-delay: calc(var(--rainbow-speed) * -0.75s);
  animation-name: rainbow-animation;
}

@keyframes rainbow-animation {
  0% {
    color: var(--rainbow-color-1);
  }
  25% {
    color: var(--rainbow-color-2);
  }
  50% {
    color: var(--rainbow-color-3);
  }
  75% {
    color: var(--rainbow-color-4);
  }
}




/* for demo page only */

body {
  font-family: sans-serif;
  background-color: whitesmoke;
}
.card {
  background-color: white;
  box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
  font-size: 2rem;
  font-weight: bold;
  display: inline-block;
  border: 1px solid lightgray;
  border-radius: 0.5rem;
  padding: 1rem;
  margin: 0.5rem;
}
<div >Stack Overflow!</div>

<div >Hello World</div>

  • Related