Web Animations API Tutorial Part 5: The Loveable Motion Path

This is Part 5 of an introductory/tutorial series on the Web Animations API coming to browsers.

IMPORTANT: The spec (and Chromium implementation) for Motion Path has changed significantly since this article was written. The following is still valid conceptually, but property names and more have changed. For the latest, please check CSS Motion Path as of October 2016.

Finally. Animating along a path… no longer just the domain of SVG.

Motion Path: Current Direction (of the Spec)

See the Pen Motion Path Infinity by Dan Wilson (@danwilson) on CodePen.

As the API specification has been worked through, motion path has appeared in different forms. One direction that initially seemed likely was the form of an Effect (like the previously discussed GroupEffect), but then a little bit of steam picked up with Motion Path as a CSS Module (with its own spec).

Therefore animating along a path will simply be another set of CSS properties that can be animated, just as opacity and tranform can. This way CSS Transitions and Keyframes can use it as well as the Web Animations API… which is great since we want as much as we can shared between these methods to give us more flexibility. Chrome and Opera have released an initial implementation, so we can actually start playing with it today even though it has not found its way to any polyfill.

Let’s break down what these properties are, how we can use them, and what things might still trip us up for now.

Motion Path Properties

There are three motion properties we will discuss. For now, to see the examples you will need to be running Chrome 46 or Opera 33.

motion-path

The starting point is motion-path which defines a path along which the element can move, following how paths work in SVG 1.1:

#motioner {
  motion-path: path("M200 200 S 200.5 200.1 348.7 184.4z");
}

This can also take a fill-rule as an optional first parameter in the path call. I recommend reading Joni Trythall’s excellent Pocket Guide to Writing SVG for a discussion on what this entails.

According to the spec, you can also use a basic shape such as circle, polygon, ellipse, and inset. These should look familiar to you if you have tried using CSS Shapes.

With Blink’s initial implementation, I’ve only seen the path() method work, so either I’ve been using shapes incorrectly or that is yet to come.

motion-offset

To drive the motion and actually place the element somewhere on the path we use motion-offset. This can either be a double length value or a percentage. So to animate from the starting point of the path to the end we set up an animation that goes from 0 to 100%. With the Web Animations API we have

var m = document.getElementById('motioner');
m.animate([
  { motionOffset: 0 },
  { motionOffset: '100%' }
], 1000);

And with CSS

#motioner {
  animation: path-animation 1s;
}
@keyframes path-animation {
  0% { 
    motion-offset: 0;
  }
  100% { 
    motion-offset: '100%';
  }
}

See the Pen CSS Motion Path Spiral by Dan Wilson (@danwilson) on CodePen.

This CodePen demo shows several dots moving along a spiral path from the outside to the inside. As each dot approaches the center it gets faster, smaller, and becomes transparent. .animate() is called twice on each dot with inifinite iterations and a delay, where one call focuses on the motion offset and the other focuses on the scaling and opacity. I broke them out to specify different easings, but they certainly could have been combined.

This approach also uses feature detection, which you will notice if you are viewing this in Safari, Firefox, Edge, or an older Chrome/Opera because you will see a message instead of the animation. There a few ways to do this, such as

var m = document.getElementById('motioner');
if (m.style.motionOffset !== undefined) { ... }

Of course, we wouldn’t want to block out users completely in a real web thang, so we can have an alternate animation (or no animation) that switches to the Motion Path animation if supported. Progressive Enhancement is a friend here, as usual.

motion-rotation

The final property is motion-rotation, and it deals with which direction the element “faces” as it moves along the path. There are four primary ways to specify this.

  • The value “auto” means the element will rotate with the path.
  • With the value “reverse” the element will also rotate with the path, but it will add 180 degress, so it will be facing backward.
  • “auto Xdeg” (or “reverse Xdeg”) will do the same except add X degrees
  • “Xdeg” will no longer rotate with the path, the element will stay fixed facing the same direction.

See the Pen CSS MotionPath by Dan Wilson (@danwilson) on CodePen.

What’s Missing?

This is a first version, of course, and the browser makers and spec writers are still discussing it all. The biggest thing I have noticed while trying this out was the lack of a way to adapt the path to different screen/container sizes.

Paths simply appear as they are defined. When working with SVG we get flexibility because we have different coordinate systems and attributes on the container like viewBox. With Motion Paths defined in CSS, the size of the path cannot be additionally modified or constrained with other properties. The width and height defined on your element apply only to the element, not its motion path. You could use media queries or JavaScript to define different paths for different criteria, but setting it up with flexibility via the motion properties is not possible yet.

Wrap Up and Next Time

We will see the direction the specification takes, but for now it’s fun to try this out and see what it might provide (and not provide). I’m gathering a collection of CSS Motion Path demos I find on CodePen, and Eric Willigers (owner of this implementation task on the Chrome development team) has a Google Doc with examples.

We will wrap up this series next time by recapping what we have discussed and taking a look at a few currently-only-in-the-spec topics.

Check out the rest of this series: