I saw this fancy scrolling effect on this website and it just blew my mind. I thought of recreating it and got somewhat successful :)
BTW, surely check this portfolio website by Ilya Kulbachny.
Setup
Run the following commands to have an initial setup to work on.
git clone https://github.com/holdmypotion/scroll-transition.git cd scroll-transition git checkout starter yarn yarn start
Final File Structure
heroSection.js
Let's start with the hero section. We'll be using framer-motion
to animate the image on scroll.
Copy paste this code in src/components/heroSection.js
import React from 'react'; // 1. import { motion, useViewportScroll, useTransform } from 'framer-motion'; import styles from '../styles/heroSection.module.css'; import heroImage from '../assets/images/5.jpeg'; export default function HeroSection({ offset = 1500 }) { // 2. const { scrollY } = useViewportScroll(); // 3. const scale = useTransform(scrollY, [0, offset], [1, 5]); const opacity = useTransform(scrollY, [0, offset], [3, 0]); const moveDown = useTransform(scrollY, [0, offset], [0, -1000]); return ( <> <div className={styles.imageContainer}> {/* 4. */} <motion.img src={heroImage} alt='Model' style={{ opacity: opacity, scale: scale, y: moveDown, }} /> </div> {/* 5. */} <div style={{ background: '#030303', height: `${offset}px` }}></div> <div style={{ background: '#030303', height: '80vh' }}></div> </> ); }
Let's break it down:
- Here we import all the sass we need from framer motion
- motion: Grants a normal JSX element super powers (extra props to work with framer motion API)
- useViewportScroll: Can be used to track the position of the scroll.
- useTransform: Can be used to change the value of a variable based on a changing value of another variable. (by default: the change is linear)
- We are using the
useViewportScroll
hook to get the vertical scroll distance in pixels - Using the
useTransform
hook to change the value of 3 variables,scale
,opacity
, andmoveDown
based on thescrollY
- Here we pass the dynamic values to the
styles
prop of the motion component. - Lastly, we are adding this empty div of height equal to the total scrolling area we set. This allows us to scroll as the above
imageContainer
is set toposition: fixed
Discussion