Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
June 21, 2019 12:36 am GMT

Today I learned how to animate a text gradient in CSS (and JavaScript)

Cover photo by Clem Onojeghuo via Unsplash.

I'm very sorry. And you're welcome.

Look at that bad boy chug. I think I set my CPU on fire making it... poor thing is really doing its best. I see why the CSS overlords didn't want to let me do this now.

Part one: Getting a text gradient

You might notice this part of the code:

@mixin lead($one, $two, $three, $four, $five, $six) {  background: linear-gradient(80deg, $one, $two, $three, $four, $five, $six);  background-clip: text;  text-fill-color: transparent;  -webkit-background-clip: text;  -webkit-text-fill-color: transparent;}

That's what's generating the actual "rainbow text" part of this disaster.

The background part is just generating the gradient itself; the good old rainbow barf you might have seen elsewhere before. Removing all the background-clip and text-fill shenanigans in that mixin makes it look like this:

The text "happy pride month" in black with a rainbow gradient background.

It's all that other stuff that makes the text look like the background.

Normally the background-clip property is used to fine-tune the appearance of background around borders and paddings and the like, but the "text" value is highly magical.

The text-fill-color is roughly equivalent to your standard color attribute. (For this pen you could just as easily substitute color: transparent, I tried and it worked.) In this case we can set it to "transparent" so that our background shows through.

So what's going on here to get the "rainbow text" is:

  • The background is turned into rainbows
  • The background is clipped so that the only part of it that shows is the part that would normally be covered by text
  • The text is made transparent so we can see the background through it

Part two: You can animate a background, but you can't make it linear-gradient

This is where everything started to go off the rails. My first approach was to slap a transition on a single container and call it a day; it would have taken about five minutes, and most of that was googling how to make the gradient clip to the background.

However

Time to try another tactic.

<div id="main" class="container lead-red">  HAPPY PRIDE MONTH</div><div id="fade" class="container lead-orange">  HAPPY PRIDE MONTH</div>

Wait, why are there two-

function intervalFunction() {  rainbowify();  setTimeout(intervalFunction, getNextTimeoutDuration());};intervalFunction();

What are you doing on an interval-

... ... ...

Oh no.

Here's the gist:

Have two nearly identical HTML elements overlap each other. The first one, #main, is on the bottom layer and is always visible; it "blinks" between gradients at a constant opacity. The second one, #fade, is on the top layer and is constantly blinking in (when aligned) and fading out (to achieve an appearance of transition using opacity).

These two are not on the same "rainbow cycle" - the #fade text is ahead of the #main by one color. JavaScript runs a loop using setInterval to juggle the classes on these two elements to keep the colors moving.

That also didn't work.

Part three: Blink in, fade out

My code looked something like this: During the main setInterval loop, attempt to halt animation with a .halt class that sets the transition-timing property to 0ms (effectively disabling transitions). I would then set the opacity to 1 to get it to "blink in", and remove the .halt class. The I would set the opacity back to 0 and let the transition do its magic. This all happened immediately, on about four lines of code.

Well, CSS transitions do not work that way. It turns out that in order for it to transition, the rendering engine needs a couple milliseconds to get its act together, regardless of what the transition property was on the element at the time.

Adding and then removing a class almost immediately is not, as it turns out, enough time.

I messed around with transition timing and other CSS for awhile before giving up and trying JavaScript. The initial JS hack of using a setTimeout( ... , 20) inside my existing setInterval loop worked... about 95% of the time. Setting the timeout lower would cause it to stutter as the transitions couldn't keep up, and setting the timeout higher would cause highly noticeable pauses in the animation. However, having weird magic numbers lying around and occasional visits from Blinky McBlinkerton weren't where I wanted to leave it...

Part four: Reducing the juddering

The first part I wanted to eliminate was that magic 20ms timeout. I googled for an eternity and came up with this:

Trigger a reflow in between removing and adding the class name.

That explains this bit:

fade.classList.add("halt");fade.classList.add("hide");fade.classList.remove("lead-" + rainbow[(i + 1) % ilen]);fade.classList.add("lead-" + rainbow[(i + 2) % ilen]);void fade.offsetWidth; // <- this one!fade.classList.remove("halt");fade.classList.remove("hide");

The next weird thing I figured I'd plan ahead for was JS timer drift. I've seen this before when building schedules and clocks; one millisecond as specified is not always one millisecond in reality, so any interval will inevitably drift further and further away from accuracy. Since I have the same timeout hardcoded into my SCSS and my JS, it would definitely look nicer if they could consistently line up. This could prevent further pauses, stutters, etc. due to timer drift.

To do this, I use setTimeout instead of setInterval, and have the timeout call a function that calls another timeout (effectively creating an interval out of timeouts). Each timeout notes when it starts, and notes the "drift" from the last timeout, and corrects itself to attempt to more accurately hit a long-term target. This would definitely be useful if I were to pivot to something like @keyframes.

In conclusion:

Thomas the tank engine side-eyeing the distance, captioned "Thomas had never seen such a mess."

This is unnecessarily complicated and runs like molasses in winter. Just make a gif or something.

But I did it, CSS overlords. I've beaten you. I've won.


Original Link: https://dev.to/tchaflich/today-i-learned-how-to-animate-a-text-gradient-in-css-and-javascript-2ehp

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To