Reputation: 93
I want to change the color of each letter of a text based on the scroll position.
The animation is the same as here (scroll down to the "Precision" section):
https://www.polestar.com/us/polestar-1/
I use React and Framer Motion. I don't have much yet, that's the only one so far.
https://codesandbox.io/s/epic-kare-khlt5f?file=/src/Example.js
Does anyone have a solution / idea how I can animate the individual letters?
Upvotes: 1
Views: 768
Reputation: 86
App.js
import Example from "./Example";
import "./styles.css";
export default function App() {
return (
<div className="App">
<Example />
</div>
);
}
style.css
body {
margin: 0;
box-sizing: border-box;
}
.section__wrapper {
max-height: 100px;
overflow-y: scroll;
}
.section__title {
font-size: 72px;
}
example.js
import "./styles.css";
import { useEffect, useRef, useState } from "react";
import { useScroll, useMot } from "framer-motion";
export default function Example() {
const targetRef = useRef(null);
const str = "Here is some text that should be animated";
const [a, setA] = useState(); //the string display in div
const [myScroll, setMyScroll] = useState(0); //scrool position
const [myColor, setMyColor] = useState(0);
//set ref scroll position by document onScroll
const handleScroll = () => {
setMyScroll(targetRef.current.scrollTop);
};
useEffect(() => {
//check after the ref exist
if (targetRef.current) {
//you can design your math
const displayLength = Math.floor(
((str.length + 10) * targetRef.current.scrollTop) /
targetRef.current.scrollHeight
);
const displayColor = 255-Math.floor(
(200 * targetRef.current.scrollTop) / targetRef.current.scrollHeight
);
// console.log(
// Math.floor(
// (str.length * targetRef.current.scrollTop) /
// targetRef.current.scrollHeight
// )
// );
// console.log(Math.floor(100*targetRef.current.scrollTop /
// targetRef.current.scrollHeight));
//set A as the "cool string"
setA(str.substring(0, displayLength));
//set color as the "cool color"
setMyColor(displayColor);
}
}, [myScroll]);
return (
<>
<div
className="section__wrapper"
ref={targetRef}
onScroll={() => {
handleScroll();
}}
>
<div>
{/* scroll content */}
<div className="section__title">1</div>
<div className="section__title">2</div>
<div className="section__title">3</div>
<div className="section__title">4</div>
<div className="section__title">5</div>
<div className="section__title">6</div>
<div className="section__title">7</div>
<div className="section__title">8</div>
</div>
</div>
{/* display the string */}
<div
className="section__title"
style={{ color: `rgb(${myColor},${myColor},${myColor})` }}
>
{a}
</div>
</>
);
}
I am not good at the css, so i let it be easier. I change your code a lots and cleaner. I just focus on the scroll top ,height and "cool string". That's it.
Upvotes: 0