Categories
React

Framer Motion — Correcting Distortions and Layout Animations

Spread the love

With the Framer Motion library, we can render animations in our React app easily.

In this article, we’ll take a look at how to get started with Framer Motion.

Scale Correction

Layout animations are performed with the transform property so we see smooth animations.

Animations may distort child elements.

We can fix this with the layout prop.

For example, we can write:

App.js

import React, { useState } from "react";
import { motion } from "framer-motion";
import "./styles.css";

export default function App() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <motion.div
      layout
      data-isOpen={isOpen}
      initial={{ borderRadius: 50 }}
      className="parent"
      onClick={() => setIsOpen(!isOpen)}
    >
      <motion.div layout className="child" />
    </motion.div>
  );
}

styles.css

html,
body {
  min-height: 100vh;
  padding: 0;
  margin: 0;
}

* {
  box-sizing: border-box;
}

body {
  background: green;
  background-repeat: no-repeat;
  display: flex;
  justify-content: center;
  align-items: center;
}

.App {
  font-family: sans-serif;
  text-align: center;
}

.parent {
  background: white;
  width: 100px;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.parent[data-isOpen="true"] {
  width: 200px;
  height: 200px;
}

.child {
  width: 40px;
  height: 40px;
  background: green;
  border-radius: 50%;
}

We animate the outer div by expanding it when we click on it.

We add the layout prop to the inner div so that we don’t get distorting when we animate the outer div.

Transforms can also distort boxShadow and borderRadius values.

To keep them constant, we can set the in the initial prop:

App.js

import React, { useState } from "react";
import { motion } from "framer-motion";
import "./styles.css";

export default function App() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <motion.div
      layout
      data-isOpen={isOpen}
      initial={{ borderRadius: 50 }}
      className="parent"
      onClick={() => setIsOpen(!isOpen)}
    >
      <motion.div layout className="child" initial={{ borderRadius: "20%" }} />
    </motion.div>
  );
}

styles.css

html,
body {
  min-height: 100vh;
  padding: 0;
  margin: 0;
}

* {
  box-sizing: border-box;
}

body {
  background: green;
  background-repeat: no-repeat;
  display: flex;
  justify-content: center;
  align-items: center;
}

.App {
  font-family: sans-serif;
  text-align: center;
}

.parent {
  background: white;
  width: 100px;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.parent[data-isOpen="true"] {
  width: 200px;
  height: 200px;
}

.child {
  width: 40px;
  height: 40px;
  background: green;
}

We set the initial prop of the child div.

And we remove the border-radius from styles.css .

Customizing Layout Animations

We can customize layout animations with the transition property.

For example, we can write:

App.js

import React, { useState } from "react";
import { motion } from "framer-motion";
import "./styles.css";

export default function App() {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <motion.div
      layout
      data-isOpen={isOpen}
      initial={{ borderRadius: 50 }}
      className="parent"
      onClick={() => setIsOpen(!isOpen)}
      transition={{
        layoutX: { duration: 0.3 },
        layoutY: { delay: 0.2, duration: 0.3 }
      }}
    >
      <motion.div layout className="child" />
    </motion.div>
  );
}

styles.css

html,
body {
  min-height: 100vh;
  padding: 0;
  margin: 0;
}
* {
  box-sizing: border-box;
}
body {
  background: green;
  background-repeat: no-repeat;
  display: flex;
  justify-content: center;
  align-items: center;
}
.App {
  font-family: sans-serif;
  text-align: center;
}
.parent {
  background: white;
  width: 100px;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.parent[data-isOpen="true"] {
  width: 200px;
  height: 200px;
}
.child {
  width: 40px;
  height: 40px;
  background: green;
  border-radius: 50%;
}

We set the transition prop to add a delay when we animate the y direction.

We also set the duration of the animation in the y direction to 0.3 seconds.

And we set the animation in the x direction to 0.3 seconds.

Conclusion

We can correct distortions with layout animations.

And we can control how layout animations are rendered with Framer Motion.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *