Animated morphing shapes in text

Jan 5

3min

In this post, I explain how I implemented a specific text animation for my portfolio's hero section. I wanted to have a colored blob animation running across a heading section, something like this:

Blog

My awesome blog

Blog

My awesome blog

Let's break down the building process into steps:

  1. Create multiple blobs in an SVG editor.
  2. Merge the blobs into an animated shape <animate> tag.
  3. Create a layout using HTML and CSS where it's possible to set custom colors for both text and blob.

#Create multiple blobs

First, I used Boxy SVG Editor to create one shape (blue in the image below) using Spline tool. After this, I duplicated the first shape and created the second and the third shapes by moving vertexes around and moving the shapes themselves. The result looks like this:

Blob

You can download this SVG file if you want to use it.

#Create an Animated Blob

To create an animated blob, you'll need to copy d attributes from each shape path inside of the values attribute of the <animate /> tag:

<path fill="currentColor">
  <animate
    attributeName="d"
    dur="25s"
    repeatCount="indefinite"
    values="
      path1; path2; path3; path1;
    "
  />
</path>

Each d attribute is separated by ;. The <animate />tag should include attributeName set to d because that's what we're animating. Animation duration is set by the dur attribute and repeatCount set to infinite will make the animation repeat indefinitely.

#Build the layout

Let's build the HTML layout for this animated text. It is rather simple:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link 
    href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap" 
    rel="stylesheet">
</head>
<body>
  <div class="animated-text">
    <div class="static-text">
      <h1>Blog</h1>
      <h2>My Awesome Blog</h2>
    </div>
    <div class="blob">
      <h1>Blog</h1>
      <h2>My Awesome Blog</h2>
    </div>
  </div>
</body>
</html>

Here, I have two divs with the same content, one for the text and one for the animated blob, wrapped in a single div with the class of animated-text.

Let's add some CSS to make the layout work.

/* RESET & CENTER CONTENT */
* {
  margin: 0;
  padding: 0;
  font-family: Inter;  
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

/* TEXT ANIMATION */
.animated-text {
 --text-color: #1e293b;
 --blob-color: #0ea5e9;  
  
  position: relative;
}

.animated-text h1, .animated-text h2 {
  font-weight: 900;
  letter-spacing: -0.05em;
  line-height: 0.9;
}

.animated-text h1 {
  font-size: 64px;
  text-transform: uppercase;
}

.animated-text h2 {
  font-size: 32px;
}

.animated-text > .static-text {
  color: var(--text-color);
}

.animated-text > .blob {
  position: absolute;
  inset: 0;
  background-clip: text;
  color: transparent;
  background-color: var(--blob-color);
  mask-repeat: no-repeat; 
  mask-image: url("data:image/svg+xml;base64,/*..embedded svg file in base64..*/}

It contains some reset and centering magic at the beginning of the file. The wrapper div has a class of animated-text that contains CSS variables for text and blob colors.

The actual magic happens within the blob class: here, I set mask-image property to the animated SVG that was created in the previous step, or, rather, I embed it in base64 encoding. I used this base64 encoder to convert the SVG to base64. Using base64 instead of utf-8 allows to escape the escape problem that's caused for single and/or double quotes within the SVG.

That's it! You can check out the whole code in this codepen.