Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Framer motion animate when element is in-view (When you scroll to element)

Is there any built-in way to make the animation start when the element is in-view (for example, when we scroll to the element)?

Framer Motion has mount animations section which says:

When a component mounts, it'll automatically animate to the values in animate if they're different from those defined in style or initial

So I couldn't really find a straight forward way to make the animation start when it comes into view.

However, I reached the only option I see for now is using Animation Controls which means I'll have to implement a listener on the scroll manually and trigger the control.start(), any easier ways are much appreciated.

like image 336
Ali Elkhateeb Avatar asked Nov 20 '19 16:11

Ali Elkhateeb


People also ask

Can I use framer motion with styled components?

Turning a styled-component into something animatable <some html element> to start using Framer Motion for that component. Animating it's as easy as adding the animate , transition , and other props you're used to adding directly to motion elements.


1 Answers

framer-motion has built-in support for this use case since version 5.3.

Here's a CodeSandbox demonstrating the pattern: https://codesandbox.io/s/framer-motion-animate-in-view-5-3-94j13

Relevant code:

function FadeInWhenVisible({ children }) {
  return (
    <motion.div
      initial="hidden"
      whileInView="visible"
      viewport={{ once: true }}
      transition={{ duration: 0.3 }}
      variants={{
        visible: { opacity: 1, scale: 1 },
        hidden: { opacity: 0, scale: 0 }
      }}
    >
      {children}
    </motion.div>
  );
}

Usage:

<FadeInWhenVisible>
  <Box />
</FadeInWhenVisible>

Previous versions:

You can currently use the imperative animation controls to achieve this effect. Intersection observers are useful to detect if an element is currently visible.

Here's a CodeSandbox demonstrating the pattern: https://codesandbox.io/s/framer-motion-animate-in-view-gqcc8.

Relevant code:

function FadeInWhenVisible({ children }) {
  const controls = useAnimation();
  const [ref, inView] = useInView();

  useEffect(() => {
    if (inView) {
      controls.start("visible");
    }
  }, [controls, inView]);

  return (
    <motion.div
      ref={ref}
      animate={controls}
      initial="hidden"
      transition={{ duration: 0.3 }}
      variants={{
        visible: { opacity: 1, scale: 1 },
        hidden: { opacity: 0, scale: 0 }
      }}
    >
      {children}
    </motion.div>
  );
}
like image 100
amann Avatar answered Oct 18 '22 22:10

amann