Animated morphing shapes in text
Jan 5
3min
Contents
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:
- Create multiple blobs in an SVG editor.
- Merge the blobs into an animated shape
<animate>
tag. - 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:
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.