Wrapper for framer-motions useScroll
hook to animate an element according to its refs container position in the viewport.
Originally inspired by coleturner's gist.
https://framed-scroll-motion.netlify.app
With npm:
npm i framed-scroll-motion
With yarn:
yarn add framed-scroll-motion
Wrap your App with the FrameProvider
. This Context provides the current window size for every framed-scroll-motion
hook.
import { FrameProvider } from 'framed-scroll-motion';
const App = () => {
return (
<FrameProvider>
// ...
</FrameProvider>
);
}
The useFramedScrollMotion
hook takes an array of keyframes as its first argument and framer motions useTransform
hook output range as the seconds argument.
The animation starts when the ref element is entering the viewport and ends when the ref has fully left the screen.
The keyframes array must contain ascending decimal values representing the refs scroll percentage in the current viewport. Keyframes and output range must be the same length.
import { useFramedScrollMotion } from 'framed-scroll-motion';
const FramedScroll = () => {
const [ref, rotate] = useFramedScrollMotion([0, 1], [0, 180]);
return (
<motion.div ref={ref} style={{ rotate }}>
Rotate
</motion.div>
);
};
To use multiple transforms corresponding to a single ref element use the useRefViewportScroll
hook. It returns an input range which you can pass to the useViewportTransform
hook to get the according motion value.
import {
useRefViewportScroll,
useViewportTransform,
} from 'framed-scroll-motion';
const FramedScroll = () => {
const [ref, inputRange] = useRefViewportScroll([-0.3, 0.3, 0.8, 1.15]);
const scale = useViewportTransform(inputRange, [0, 1, 1, 0]);
const opacity = useViewportTransform(inputRange, [0, 1, 1, 0]);
return (
<motion.div ref={ref} style={{ scale, opacity }}>
Scale Opacity
</motion.div>
);
};
- Better demo
- Better documentation