Adobe Creative Cloud

July 17, 2015 /Code /

How to Create Squiggly Text with SVG Filters

In this post, I’m going to walk you through how to create a squiggly text effect using SVG Filters and CSS. This effect can be useful when you want to make things a bit more playful. This tutorial can also serve as an introduction to, and exploration of, SVG filters.

SVG Filters

SVG Filters are filter effects that were originally developed for SVG, but can be applied to regular DOM elements through the CSS filter property. They allow for much more flexibility than regular CSS filters due to the ability to chain filters together, as well as the greater variety of base effects (which are called primitives).

To illustrate how they work, here is a drop shadow effect created with SVG Filters:

<div class="element"></div>

<!-- We need to declare our SVG filters inside
an SVG element -->
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="drop-shadow">
      <!-- Get the element's graphic, through the SourceGraphic
        keyword in the 'in' attribute, apply a blur filter, and
        name the output using the 'result' attribute -->
      <feGaussianBlur in="SourceGraphic" stdDeviation="7" result="shadow" />

      <!-- Get the previous output, shift its position, and output
        with the same name -->
      <feOffset in="shadow" dx="3" dy="4" result="shadow" />

      <!-- Darken the result of the previous filters -->
      <feColorMatrix in="shadow" mode="matrix" values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.6 0" result="shadow" />

      <!-- Put the original graphics atop the shadow we made -->
      <feBlend in="SourceGraphic" in2="shadow" />
    </filter>
  </defs>
</svg>

Then we just apply it to an element with CSS:

.element{
  filter:url('#drop-shadow');
}

See the Pen svg drop shadow demonstration by Lucas Bebber (@lbebber) on CodePen.

More information about SVG Filters can be found here.

Squiggle It Up

There are two filter primitives we need in order to make the squiggle effect work: feDisplacementMap, which distorts an object based on an image map, and feTurbulence, which will generate the noisy image map we need for the distortion.

feDisplacementMap takes two inputs: in, which will be the image to be distorted, and in2, which is an image that tells the filter where to distort, based on its lightness. Another important attribute is the scale parameter, which sets the maximum distortion the filter will apply.

displacement

The feTurbulence filter generates a random, noisy image. It has several parameters that help us adjust the result to our needs, and a seed attribute that lets us change the base number it uses for its randomization.

This filter will be useful in creating the displacement maps we need in order to make a nice wiggle effect.

See the Pen feTurbulence demonstration by Lucas Bebber (@lbebber) on CodePen.

To use both filters together is fairly simple. We make the feTurbulence filter first, then we take its output and put it into our feDisplacementMap‘s in2 attribute.

<filter id="squiggly">
      <feTurbulence baseFrequency="0.02" numOctaves="3" result="noise" seed="2"/>
      <feDisplacementMap in="SourceGraphic" in2="noise" scale="10" />
</filter>

See the Pen Squiggly Text Experiment by Lucas Bebber (@lbebber) on CodePen.

Animating

Now, we could simply animate the seed parameter (which sets its randomization) of our feTurbulence filter and call it a day. The problem is that this is bad for performance; the browser will have to generate a new random image every frame, and then make a new feDisplacementMap based on it.

What we can do to get around that is to simply make a bunch of copies of the entire filter with slightly different parameters, and alternate between then. This way the browser will only have to render most of the animation once.

<filter id="squiggly-0">
  <feTurbulence baseFrequency="0.02" numOctaves="3" result="noise" seed="0"/>
  <feDisplacementMap id="displacement" in="SourceGraphic" in2="noise" scale="6" />
</filter>
<filter id="squiggly-1">
  <feTurbulence baseFrequency="0.02" numOctaves="3" result="noise" seed="1"/>
  <feDisplacementMap in="SourceGraphic" in2="noise" scale="8" />
</filter>
<!-- make as many copies as you want, changing the seed and the scale attributes -->
@keyframes squiggly-anim {
  0% {
    filter: url("#squiggly-0");
  }
  25% {
    filter: url("#squiggly-1");
  }
  50% {
    filter: url("#squiggly-2");
  }
  75% {
    filter: url("#squiggly-3");
  }
  100% {
    filter: url("#squiggly-4");
  }
}
.squiggly{
  animation: squiggly-anim 0.4s linear infinite;
}

See the Pen Squiggly Text Experiment by Lucas Bebber (@lbebber) on CodePen.

And with that we are done! Please note that these filters are not supported by every browser, and even fewer support animating them like this. These effects can also be quite heavy, so be careful!

Code