I recently created a new page on this website. From an early time in my frontend journey, I have been amazed by the websites that are featured on awwwards and I wanted to create something fancy like them.
Here's how I did it.
Let's take a look again at what we're trying to build here:
Hello there!let's break down what's happening here:
We can animate the color changing of the text by using transition
:
CSS1transition-property: color;2transition-duration: 5s;3transition-timing-function: linear;45/* or in one line */6transition: color 5s linear;
And since I'm using styled-components
, we can put this in a re-usable CSS string:
JSX1import { css } from "styled-components";23const WaveMixin = css`4 transition-property: color;5 transition-duration: 5s;6 transition-timing-function: linear;7`;
But this doesn't do anything at the moment — to actually change the color, we will need to update the color of the <span>
that we are targeting after it has been rendered to the screen.
Let's start writing our little wrapper component for this:
JSX1// usage2<Highlight>Hello there!</Highlight>;34const Highlight = ({ children }) => {5 return <Wave>{children}</Wave>;6};78// import styled, { css } from "styled-components";9const WaveMixin = css`10 transition-property: color;11 transition-duration: 5s;12 transition-timing-function: linear;13`;1415const Wave = styled.span`16 ${WaveMixin}17`;
And now we change the color once the component has mounted:
JSXHello there!1<Highlight>Hello there!</Highlight>;23let root: HTMLElement;45const getNewColor = () => {6 const h = random(1, 360);7 const s = random(80, 90);8 const l = random(50, 60);910 return `hsl(${h}, ${s}%, ${l}%)`;11};1213const Highlight = ({ children }) => {14 const changeColor = () => {15 const newColor = getNewColor();1617 if (root === undefined) root = document?.documentElement;18 root.style.setProperty("--color-chameleon", newColor);19 };2021 useEffect(() => {22 changeColor();23 }, []);2425 return <Wave>{children}</Wave>;26};2728const WaveMixin = css`29 color: var(--color-chameleon);30 transition-property: color;31 transition-duration: 5s;32 transition-timing-function: linear;33`;3435const Wave = styled.span`36 ${WaveMixin}37`;
Huh, that didn't seem to work out 🤔 but that's because the transition already ran since the above live example was already "mounted" by the time you scrolled down to it.
To keep changing the color after a pre-defined interval, we'll be defining our very own useInterval
custom hook:
JSX1const useInterval = (callback, delay) => {2 const savedCallback = useRef();34 useEffect(() => {5 savedCallback.current = callback;6 }, [callback]);78 useEffect(() => {9 const handler = (...args) => savedCallback.current(...args);1011 if (delay !== null) {12 const intervalId = setInterval(handler, delay);13 return () => clearInterval(intervalId);14 }15 }, [delay]);16};
Let's now use this hook to change the color of our text just as it completes its transition.
JSXHello there!1import { useInterval } from "utils/hooks";23const Highlight = ({ children }) => {4 const changeColor = () => {5 const newColor = getNewColor();67 if (root === undefined) root = document?.documentElement;8 root.style.setProperty("--color-chameleon", newColor);9 };1011 useEffect(() => {12 changeColor();13 }, []);1415 useInterval(() => {16 changeColor();17 }, 5000);1819 return <Wave>{children}</Wave>;20};
Voila! ✨
There we go. What's great is that you can also use this to highlight link, like so:
I'm really glad with how the effect turned out, and it was also easier to accomplish because I was using CSS-in-JS. It's great to see how powerful tools like styled-components can be! You can check the effect out in action and see it in all its glory 😄
Have a good one 👋
Published: May 11, 2021
No views yet. Wait what, How? 🤔