Creating Morphing Animations with CSS clip-path

Learn how to implement morphing, a technique for transforming one appearance into another, using CSS.

Photo by Thomas Renaud on Unsplash

I’ve been quite intrigued by morphing lately. As usual, when I find things to deep dive into, the energy so often ends up in demos (pens) on my Codepen profile. Codepen is the perfect place to channel one’s creativity. It’s a community filled with new ideas and sweet people. At Codepen, sharing is central. Here most strive to improve, to grow with others.

This article is about, what I call, in lack of a better term, clip-path morphing. It will discuss a pen on my Codepen account called the Play Pause Button and the technique behind it. Here is a short video of the animation that we’ll dig into:

Video of the demo Play Pause Button

What is morphing?

Morphing is a technique where you transform one appearance into another. It’s a shape-shifting animation where a two-dimensional object, say an image or a figure or similar, turns into a different shape.

Technically it’s the interpolation from one set of coordinates to another. For the sake of simplicity, this article regards the starting shape and the end state as collections of the same amount of nodes. In theory, it is possible to create the effect with different amount of nodes. Having the same number of nodes in the starting point/shape as in the final figure simplifies things a lot. It does so without compromising the coolness of the effect.

Below is an example of a basic clip-path morphing animation. The video shows a shape alternating between a box and a star. The collective movement of all nodes together is what makes up the effect. Some nodes move a long distance, and some not at all. This characteristic is typical for morphing. It’s a trait that distinguishes it from other kinds of animations.

Morphing in SVG

Most of the morphing effects, seen on the web today, comes in SVG. Vector graphics are all about coordinates. SVG is thus a natural starting point to create morphing effects.

With SVG, you have quite sophisticated tools at your hands. These tools help out to place objects in different layers, create different coloring, rearrangement of objects and sizes, etc. Especially interesting is the editing of shapes where one can manipulate the separate nodes and alter figures.

The two steps of creating the morphing effect

Creating a Morphing animation can, in rough terms, be divided into the following two activities:

Modeling

Animation

Modeling refers to the act of creating different vector patterns in the Morphing effect. I almost always start by creating the shapes in Inkscape, a vector editor. The same goes for the demo discussed in this article. It’s fundamentally an SVG object that I’ve partly ported to CSS.

Modeling the play/pause button

The animation in the demo consists of two separate shapes. What we’re looking at is an animation between a play symbol and a pause symbol. The play symbol comes as a triangle with rounded corners. The pause symbol is quite different; it consists of two parallel bars. As the two parts come in an uneven amount of shapes, two vs. one, we need to combine the two somehow to create the effect. The easiest way is to split the play symbol, as seen above, into two equal parts. Using two even symmetrical parts in animation is generally a good idea. There is something about symmetry. It usually creates, to the eye, a pleasing effect. Last but not least, there’s a slight rotation to account for the difference in the angle and placement.

Below is a figure of what the model of half the play symbol looks like in a vector editor.

Half the play symbol

Let’s zoom in a bit and have a look at the composition of the shape. Each half consists of 64 nodes each. Note the dense amount of nodes on the left side. The uneven placement of nodes here is deliberate. Nodes are more concentrated on the left side. This placement adds to the effect. The bottom corner will seemingly move when the triangle changes its shape. That is when three corners transform into four.

Zoomed-in view of the nodes in the half of play symbol

Let’s have a look at what the model looks like in code:

// Play/pause model

<svg ...>

<circle ... /> /* red circle */

<path d="..." /> /* Half play symbol */

<path d="..." /> /* Half play symbol */

<path d="..." /> /* Pause bar, left */

<path d="..." /> /* Pause bar, right */

</svg>

Making things move

Animation subsequently means the actual transformation, animating the starting shape from its starting point to the final figure. Creating movement in the SVG space is, so far, a manual process. Here one needs to interpolate all the separate coordinates manually. One way to accomplish this is, for instance, with Javascript, using the requestAnimationFrame API call. With the callback function, one can calculate values for each frame. However, creating manual animations is cumbersome and takes time to set up. Another option is to use an animation framework. Doing so relieves you of some of the burdens to build the animation ground up. Either way, you’ll somehow still need to set up and initiate the animation programmatically. In short, an effort is necessary.

What is this clip-path morphing?

CSS Clip-path morphing is very similar to morphing in SVG. There is an interesting distinction to make, though. The execution takes place in the CSS realm rather than in the SVG space. Moving to CSS makes it possible to leverage from the smart CSS transition engine. The engine practically does all of the heavy lifting. It covers the complete animation step and, which is important too, it does so natively. Native animations are accelerated and naturally performant.

Another thing we get for free is the complete interpolation of the full set of coordinates. The engine will dissect the collection and separately handle and interpolate each of the coordinates. The only thing we need to do is to provide the browser the starting shape and the end-state. In contrast to SVG, we need to do very little to make things move. In code, we need one line to get an animation up and running. Here’s an example:

.animated {

transition: clip-path 500ms;

}

Now, if we want to, we can add the start and end states. The easiest way to do that is by using a new state, a CSS class. For the sake of the example, let’s use the state active, which is the same state used in the demo.

.animated {

transition: clip-path 500ms;

clip-path: polygon(...); // start state

} .active .animated {

clip-path: polygon(...); // end state

}

Once the animation is in place, we only need a trigger to start the animation. This trigger can, in essence, be an event like, e.g., a timer, a touch, or a mouseover event. A simple way to activate the animation is by adding a click toggle event handler.

<div class="animated" onclick="this.classList.toggle('active')">

...

</div>

The browser can, besides the transformation also, through the transition rule, apply easing. Easing is the icing on the cake that makes motion look a lot smoother and realistic. You get so much for free. The optimized workflow is the principal reason for moving to CSS space.

Dev Tools FTW

As if the above was not enough, there’s also a great benefit using clipping paths in the Dev Tools. They provide inspection and direct manipulation of CSS clip-path rule. With the Dev Tools at your hands, you can test out animations directly in the roles editor. The inspector makes it even easier to iterate and try out different shapes.

Below is a video that demonstrates how easy it is to try out different morphing animations in CSS:

Manipulating shapes in the roles editor

Here are two other strong arguments for working with vectors in CSS

Firefox path editor makes it possible to manipulate clipping paths from the inspector

The Dev Tools support recording animations, which is perfect for finetuning animations

Moving to CSS space.

The conversion to CSS is an under-the-hood change. The idea is to create a substitute markup that produces the same visual output as the original markup. Below is an illustration in pseudo-code of what such a conversion could look like.

/* From SVG */

<svg ...>

<path d="..." />

</svg> /* To CSS */

<div style="clip-path: polygon(...)"></div>

Clipping paths supports a wide range of different methods. The most suited method, due to similarities in the format, is the polygon. Polygons do exist in SVG. However, their use is rare. For instance, the vector editor I use, Inkscape, works with paths and normally stores its output as paths. Thus, we need a way to go from paths to polygons. Or, in more detail, to convert the path descriptor (d) to a clip-path polygon.

There are similarities between the two formats. If an SVG path comes strictly without curves, then the two formats are very similar. The difference lays then mostly in a slight variation in syntax. I’ve made a habit of creating my morphing models without any curves. I.e., creating models with straight lines stored in absolute coordinates. In this way, with constraints in the format, the conversion will require a lot less.

Once, everything is properly prepared, I use a Nodejs script to do the actual conversion. Let’s look at an example in code. Below is a conversion of a star figure.

star figure to convert from SVG to CSS

And in code:

<path d="M 73.924957,90 49.42372,75.971326 24.48224,89.124336 29.669821,60.42209 10,39.681618 37.707342,35.971327 50.492205,10 62.4287,36.409157 90,41.098468 69.669822,61.130517 Z" /> /* Converts to */ <div style="clip-path: polygon(73.92496% 90%, 49.42372% 75.97133%, 24.48224% 89.12434%, 29.66982% 60.42209%, 10% 39.68162%, 37.70734% 35.97133%, 50.4922% 10%, 62.4287% 36.40916%, 90% 41.09847%, 69.66982% 61.13052%);"></div>

Below is another neat way of how to do the conversion with curves.

A glimpse into the future

There’s a supercharged upgrade around the corner. Namely, clip-path path(). Yes, I know, the name is even worse than clip-path morphing. However, this feature is the next generation SVG to CSS conversion. Once browsers fully support clip-path: path(), it’s going to be a breeze to go from SVG to CSS. In essence, the two will be interoperable. Below is what the actual support looks like at the moment. At the time of writing, only Firefox supports the rule.

The source

The Play Pause Button demo on Codepen

TLDR;