
29 October 2023
Moving Abroad: A Challenging yet Rewarding Endeavor
If you've ever thought about leaving home and moving abroad, you'll now how tough it can be. I've found it to be great, but not without challenges.
Published on 19 August 2023
In this blog post I’ll show you how to create a fun rolling rainbow text effect like this with just CSS! Although I warmly recommend also using a bit of HTML templating to make it easier to write the text.
If you’re just interested in the end result, you can skip to the end of the post to see the final code. I understand.
To attain the desired effect, apply a CSS animation that transitions through rainbow colors, with a delayed start for scroll effect.
Split the input string to stagger the animation, making each letter an individual element. For example, simon
becomes:
<span>
<span>s</span>
<span>i</span>
<span>m</span>
<span>o</span>
<span>n</span>
</span>
While you are allowed to write this by hand, it’s not so fun. Here’s how you convert a string to a group of spans with JSX:
{[...text].map((letter, i) => {
return letter === ' ' ? ' ' : <span style={`--delay: ${i*50}ms`}>{letter}</span>
})}
Spaces are left as is because they can’t change colour anyway.
On each span, a CSS variable is set that increases the start delay depending on the position of the letter in string. This is the magic that creates the scrolling effect.
First thing that’s needed is a CSS animation that fades through the colours of the rainbow:
@keyframes rainbow {
0% {
color: #e81416;
}
16% {
color: #ffa500;
}
33% {
color: #faeb36;
}
50% {
color: #79c314;
}
66% {
color: #487de7;
}
83% {
color: #4b369d;
}
92% {
color: #70369d;
}
100% {
color: #e81416;
}
}
This animation starts and ends at red.
Next we’ll need to apply the animation to each span element, delaying the start time by the --delay
variable.
.rainbow:hover span {
animation: rainbow 5s infinite;
animation-delay: var(--delay);
}
Putting it all together it looks like this:
HOVER FOR FUN
So it looks awesome, yay! But there is a slight problem… Because of the delay we added before, the letters are just chilling in white before the animation starts.
The fix is simple, just one character in fact. The neat thing about the animation delay is that you can delay it by negative amount.
In the context of looping animations, a negative delay essentially means the animation starts not from its initial state, but partway through. This is because it’s as if the animation has already been playing for the animation duration (5s) minus the delay (i * 50ms).
Let’s apply a negative delay instead:
<span style={`--delay: -${i * 50}ms`}>{letter}</span>
HOVER FOR FUN
The values I’ve provided are what I’ve found to work well.
It may be difficult to visually imagine the exact effect the animation speed vs the delay has, so here are two examples to help you out.
The following has a much higher delay of 500ms.
HOVER FOR FUN
As you can see this leads to more rainbow at a time.
The following has a much faster animation of 1s.
HOVER FOR FUN
Gee willikers, that’s fast! And it makes a little nauseous, somehow.
If you just want to copy and paste the code, here’s the code for an Astro component.
---
interface Props {
text: string;
element?: 'p' | 'span';
speed?: number;
}
const { text, speed = 1, element: Element = 'span' } = Astro.props;
---
<style lang="scss">
@keyframes rainbow {
0% {
color: #e81416;
}
16% {
color: #ffa500;
}
33% {
color: #faeb36;
}
50% {
color: #79c314;
}
66% {
color: #487de7;
}
83% {
color: #4b369d;
}
92% {
color: #70369d;
}
100% {
color: #e81416;
}
}
.rainbow:hover span {
animation: rainbow calc(10s * var(--speed)) infinite;
animation-delay: var(--delay);
}
</style>
<Element style={`--speed: ${speed}`} class="rainbow">
{[...text].map((letter, i) => {
return letter === ' ' ? ' ' : <span style={`--delay: -${i*100}ms`}>{letter}</span>
})}
</Element>
29 October 2023
If you've ever thought about leaving home and moving abroad, you'll now how tough it can be. I've found it to be great, but not without challenges.
13 August 2023
After nearly losing my mind manually adjusting monitor brightness, I finally built an automatic solution
20 March 2023
Using modern Machine Learning models not for something useful, but for something silly instead