Crazy Ones & Framer Motion
3 min read
I have an awesome typographical poster on my wall made up from Apple's iconic Think Different Commercial...
I've had this for so long I cant even remember where it came from but I really love the styles and the way it's put together. I decided it would be cool to try and recreate it using Framer Motion and React.
The Result
This short video showcases the scrolling effects on the poster, with various animations triggered based on the scroll position.
You can check out the demo here.
Framer Motion useScroll
Framer Motion is a popular animation library for React applications that makes it easy to create fluid animations and interactions. The useScroll hook allows you to manipulate elements based on the user's scroll position.
Basic Example
First, we need to set up a basic page with a few inline styles and imports:
import { useRef } from "react";
import { motion, useScroll } from "framer-motion";
export default function App() {
return (
<div
style={{
fontFamily: "sans-serif",
marginBottom: "1000px",
}}
>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "100vh",
margin: "0 auto",
textAlign: "center",
}}
>
<h1 style={{ fontSize: "32px" }}>Scroll down</h1>
</div>
</div>
);
}
We intentionally set the container to 100vh and add a large bottom margin to create more scrollable area.
Next, let's create a simple component that will scale based on the scroll position:
const BoxScale = () => {
const ref = React.useRef(null);
const { scrollYProgress } = useScroll({ target: ref });
const scale = useTransform(scrollYProgress, [0, 1], [1, 0]);
return (
<section
style={{
height: "100vh",
}}
>
<motion.div
ref={ref}
style={{
width: "150px",
height: "150px",
borderRadius: "1em",
backgroundColor: "#77037B",
marginLeft: "auto",
marginRight: "auto",
x: -50,
scale,
}}
/>
</section>
);
};
useScroll
This hook allows us to access the page's scroll position. We specifically set a target to track the progress of this element in the viewport. Check out the docs here.useTransform
This helper function enables us to map a value from one range to another. In this case, we are simply mapping the scroll progress from 0 to 1 to a scale value from 1 to 0 .Check out the docs here.
Another Example
Let's create another box that will move along the x-axis as the page scrolls:
const BoxXPos = () => {
const ref = React.useRef(null);
const { scrollYProgress } = useScroll({ target: ref });
const translateX = useTransform(
scrollYProgress,
[0, 0.5, 1],
["-100%", "0%", "100%"]
);
return (
<section
style={{
height: "100vh",
}}
>
<motion.div
ref={ref}
style={{
width: "150px",
height: "150px",
borderRadius: "1em",
backgroundColor: "#009FBD",
marginLeft: "auto",
marginRight: "auto",
translateX,
}}
/>
</section>
);
};
Similar to the previous example, we use useScroll
to track the scroll position and then employ useTransform
to map the scroll progress to a translateX
value that we pass to the box.
Code Sandbox
Feel free to explore and modify the code provided in this CodeSandbox.
Crazy Ones Example
And if you'd like to play with the Crazy Ones SVG I made, wwhich extends the principles discussed above, you can check out the playground here.