#235: Animations, Animations, Animations!

Robin: This week I’ve been thinking a lot about Framer Motion. It’s a library designed to make beautiful and complex animations on the web much easier than they would be otherwise. It’s also worth taking a look at the website because, just gosh darn, it is beautiful.

I haven’t built anything with it yet but some of my pals at Sentry have been redesigning our onboarding flows and they used Framer Motion to create some absolutely drop-dead gorgeous animations when combined with our ever-so-lovely illustrations. In fact, all this almost makes me mad because of how good it is.

A few elements appear when the page loads, while the top and bottom sections snap in from the sides. Once that’s done, the light in the corner begins to swing from side to side and then, once you click the button, everything flies up and away. On the next page, the title swishes into view and the text beneath it clicks up satisfyingly.

There’s so much going on with these animations and yet somehow it isn’t annoying at all. To me, these animations makes it feel as if I can trust Sentry— if folks are willing to spend time on the tiny details like this then I’m more likely to trust them with the product, too. Anyway, I didn’t work on this project at all but I was fascinated by how the team built this thing. Evan Purkhiser, the engineer at Sentry that built it, walked me through why he decided to use Framer Motion in the first place and what made it so helpful.

Chris did a video on Framer Motion with creator Matt Perry a while back.

Evan first pointed to the fact that it’s extremely difficult to tie animations together with CSS alone. A lot of the time when we trigger an animation we want another completely unrelated thing to fire at the same time. With CSS all we have are keyframe animations.

First you define the animation:

@keyframes pop {
  0% {
    transform: scale(0);
  } 100% {
    transform: scale(1)
  }
}

Then you apply it to an element:

.element {
  animation: pop 1s ease infinite forwards;
}

This covers a lot of animation use cases (and we even have a mini guide just about animations that goes into a lot more detail). But! What if we want to make another element start an animation once this one ends? Well, that’s where things get a bit bonkers in CSS — we’d have to add animation-delay all over the place and that becomes unmaintainable (although… you might wanna take a look at Mads Stoumann’s ideas with CSS custom properties and animations, which might open some doors here).

The magical thing about Framer Motion is that it’s relatively easy to make one animation begin when another one ends. Not only that, but you can control the animations of child elements and how they stagger via the parent element. This is something that’s just impossible with CSS today.

Here’s how you create a Framer Motion component. Let’s say you have a component in /components/Card.js that looks like this:

import { motion } from "framer-motion";

export default function Card() {
  return (
    <motion.div animate={{ scale: 1.1 }}>
      This is a card
    </motion.div>
  );
}

See that <motion.div> bit? That’s how you tell Framer Motion that this is an animatable element and also what HTML element you want to render. It looks weird, but you get used to it after a while. Also, that animate prop attached to it tells the Motion component to immediately scale by 1.1. But we could make it do that on hover or on tap instead:

export default function Card() {
  return (
    <motion.div whileHover={{ scale: 1.1 }}>
      This is a card
    </motion.div>
  );
}

I really like this syntax and it reminds me somewhat of Vue’s attributes. But anyway, I’m going to keep experimenting with Framer Motion and write a more in-depth post about how to get started, as well as how to tie different animated child elements together because that’s where the real magic lies.


Play and pause CSS animations

Speaking of animations, here’s how to play and pause CSS animations with Custom Properties. Letting folks pause the animations on our websites is always a good idea for accessibility reasons. But also this is a good reminder from Mads Stoumann:

Recently, while working on the CSS-powered slideshow you’ll see later in this article, I was inspecting the animations in the Layers panel of DevTools. I noticed something interesting I’d never thought about before: animations not currently in the viewport were still running!

Maybe it’s not that unexpected. We know videos do that. Videos just go on until you pause them. But it made me wonder if these playing animations still use the CPU/GPU? Do they consume unnecessary processing power, slowing down other parts of the page?

Inspecting frames in the Performance panel in DevTools didn’t shed any more light on this since I couldn’t see “offscreen”-frames. But, when I scrolled away from my “CSS Only Slideshow” at the first slide, then waited and scrolled back, it was at slide five. The animation hadn’t paused. Animations just run and run, until you pause them.


CSS Scroll-Linked Animations

Have you ever heard about CSS Scroll-Linked Animations? It’s a new API “for creating animations that are tied to the scroll offset of a scroll container.” That’s really hard to grap and so I think an example is required for it all to click. To do that you have to download Chrome Canary, head to chrome://flags/ and then turn on Experimental Web Platform features (phew!). Once that’s done you can finally check out how the API works with this Pen:

It’s a pretty remarkable and flexible API that I’m excited to start experimenting with soon.

Bramus has been doing other stuff with these scroll-linked animations. Here’s the start of a thread:


A website in a single HTML file

Okay, this is just straight up neat as heck. An entire website within a single HTML file. By clicking the links in the navigation it’ll immediately show the content — and look as if a new page has loaded — thanks to a nifty trick with the :target CSS pseudo selector.

So you have a bunch of HTML sections that like this:

<section id="contact">
   Contact me!
</section>

With links that look like this:

<a href="#contact">Contact</a>

By default the sections are set to display: none, but once that link is clicked, the following styles are applied:

section:target {
  display: block;
}

I can definitely seeing myself stealing this idea for smaller websites in the future.


New in Chrome 88: aspect-ratio

Geoff Graham has the scoop on Chrome 88 and has an excellent description of why the brand new aspect-ratio CSS property that comes with it is an important one. (Safari Technical Preview 118 has it as well.) In fact, I think we mentioned it in the newsletter not so long ago but it’s definitely worth reading Chris’s first look at aspect-ratio because it has an excellent breakdown of how to use it.


WPCourses from Automattic

Podcasting for Beginners joins the lineup of courses available on WordPress.com Courses alongside Blogging for Beginners. The course is a $99 yearly subscription, which provides access to: 

  • On-demand video content — updated annually (6 hours of original recordings)
  • Quarterly meetups led by the WordPress.com team
  • Regular office hours with WordPress Happiness Engineers to answer your questions
  • Certificate of completion
  • Access to an exclusive online podcasting community

Use code Chris25 for 25% either course.


[Chris]: This CSS Selector Practice interactive (I suppose we can call it a game since there is a score, after all) is pretty fun. If you were hiring someone for a CSS role, watching them do this quiz while talking their way through it would be an awesome technical interview. I thought the same thing reading Jeremey’s Get safe, about GET and POST requests on the web. Asking a potential web builder hire (front-end, back-end, or otherwise) about GET and POST would be great interview stuff. Bramus made a CSS properties test in response to Paul Foster’s HTML tag test. These are fun too, but more about rote memorization, probably making them less useful in an interview situation.