CSS vs. SVG: Graphical Text Effects

This post is the first in a series of posts exploring techniques and examples that can be achieved using both CSS and SVG, and compares them both. Since I am biased to SVG, this series is really intended to prove that SVG — because of its nature as both an image and a document format — is simply better than CSS when it comes to solving certain design problems on the web. But to keep an objective point of view, we will be weighing the pros and cons of each technique and find out where and when CSS or SVG can serve as a better tool to the design goals at hand.

In this article, we’re going to go over a few techniques for creating graphical text effects for the web using CSS and using SVG.

Graphical Text Effects with CSS

The Old CSS Way

Some years ago, we used to hack our way into creating visually appealing text on the web by not creating that text on the web, but by simply placing an image of that effect in stead of a piece of text that we would otherwise want to be graphical.

This concept of showing an image of the text where the text would show on the screen makes it possible to display a nice textual effect when we did not have the technology to achieve it (although that’s not entirely true because SVG has been around for way longer than that), and the technique is known as the “image replacement” technique.

Assume you have an h1 heading you want to replace with the image showing the same piece of text with that impressive graphical effect. The way you would do that using CSS looks like this:

h1.hide-text {
    text-indent: 100%;
    white-space: nowrap;
    overflow: hidden;
    background-image: url(…);
}

The text indentation makes sure the content of the heading exceeds its own boundaries and overflows them, and the hidden overflow value makes sure it gets cut off outside those boundaries and does not show up. So, you end up with a rectangular area (of the h1) that has no text showing inside of it.

Then the heading gets a background image which, predictably, is the image of that text that you would have created in a graphics editor such as Photoshop, for example.

So, the rectangular area of the heading is rendered and shown on the screen, without the text content inside it, and with the background image showing the graphical text inside. Neat. That’s all you needed to do to display nice graphical text effects.

The above method is called the Kellum Method since it was written by Scott Kellum and it replaced an older, not very good method that developers used before. Indeed, there were quite a few image replacement techniques back then, and the Kellum method replaced most of them because it was the “best” among the options available back then.


Not only does this technique make the text unselectable by the user (because the text inside the image cannot be selected), but it is also a hack, in the end, so new CSS properties were introduced to help achieve similar effects without having to resort to image replacement techniques..

The New CSS Ways

There are many, many text effects that can be created, including squiggly text effects that Lucas Bebber wrote about in a previous article here on the Dreamweaver blog. That said, the most commonly used text effects are either texture-filled text effects or simply textured text—or text that seemingly blends with its background.

Texture-filled Text

css-background-clip

Using the CSS background-clip property, we can fill a piece of text with a texture from an image. This property determines an element’s background painting area, which is the area within which the background is painted. By default, the background extends all the way to the border of an element with a default value of border-box, and it can take other values like padding-box and content-box, which are self-explanatory.

The background-clip property was extended in Webkit with a fourth value, text, which causes the background image to clip to foreground text. Then, by giving the text a transparent color using the Webkit-only property -webkit-text-fill-color, the background image will show through the text, thus completing the clipping effect.

For example, to clip an element’s background to the contents of the text inside of it, you would give that element a class and then apply these styles to it:

.clippedElement {
  /* background image that will serve as text fill */
  background: url(path/to/your/image.jpg) no-repeat center center;
    /* -webkit-background-clip clips the background of the element to the text */
    -webkit-text-fill-color: transparent; /* overrides the white text color in webkit browsers */
    -webkit-background-clip: text;

  /* general styles */
    background-size: 100% auto;
    color: #fff;
    text-align: center;
    padding: 2em;
}

Unfortunately, as you can see from the prefixes used, these properties currently only work in the handful of browsers that support them, so they won’t work in Firefox or IE, for example.

So, if we were to go back to our previous h1 that has a background applied to it, we wouldn’t have to hide the text anymore to show texture-filled text on the page. Instead, we wrap the heading in a div, give that div the background image that we want to use as a fill for the text, and then clip that background to the shape of the text using the above CSS properties.

The following is a live demo of this technique in action. Make sure you view it in Chrome, Safari or Opera to see it working.

See the Pen 362ec4667abd7180c298f0f1061573ed by Sara Soueidan (@SaraSoueidan) on CodePen.

For non-supporting browsers, you can revert to a simple image with text on top of it; just make sure the text color goes well with the background and does not cause any visual reading problems.

Note that the background image can be any image, including a CSS gradient because that, too, is an image. You can learn all about CSS gradients here.

 

Textured Text (Blending with Background)

Next, we’re going to use CSS masks to create the following effect where the text has some of its parts “erased” off:

css-mask

When using CSS masks, we’re making the text take the shape of its mask image, instead of making the image take the shape of (or be clipped to the shape of) the text.

The above effect uses the following mask image that I borrowed from this article I wrote on Codrops over a year ago. The image is used as a mask to mask areas of the text so that the background behind it shows through. If you choose the proper mask texture that goes with that of the background, you can achieve a nice seamless blending effect. Our mask image is made up of a bunch of “splashes” of paint. For sake of simplicity, we’re not doing any “blending” per se, only applying the splatter texture to the text.

splatter-mask

The mask image can be any image you want, including a gradient.

When you apply a CSS mask to your text, or to any other content, the text will be visible where the black areas are, and the parts where the mask image is transparent the text will not show. This is because the default type of the mask image used in CSS is an alpha mask, not a luminance mask; and since we provided an alpha mask, the dark areas will be used to define the painting area for the text.

In the case of a gradient that goes from black to transparent, for example, the masked element would be fully opaque where the gradient is black, then becomes translucent and gradually fades out where the gradient becomes transparent.

The CSS mask-image property is used to reference the mask image that we will apply to our text.

h1 {
    /* the line that applies the splatter effect */
    mask-image: url(../img/splatter-mask_1.png); 

/* any general styles go here like font family, alignment, etc. */
}

At the time of writing of this article, CSS masks are not supported too well either. Firefox only supports SVG masks and webkit browsers require the webkit prefix and only support two properties of the entire Masking specification. For a detailed look at browser support, refer to this support table.

So this is yet another way to accomplish textured text in CSS, but it is also not reliable at this time.

The following is a live demo of the above technique (view in a webkit-based browser):

 

See the Pen 75a243d2c0072a8f0bea903a0f8f9576 by Sara Soueidan (@SaraSoueidan) on CodePen.

If you want to try the gradient mask image out, replace the mask-image declaration with this line:

mask-image: linear-gradient(black, transparent);

to see the text fade out. This is how a texture can be applied to an element or a piece of text using CSS.

With SVG, things are looking much better…

Graphical Text with SVG

SVG is awesome. (I had to say that.) Now, for the sake of brevity, we will dig right into the code and explain it as we go.

When working in SVG, both the text and the effects we apply to it will be defined inside an <svg> element…

Texture-filled Text

To fill a piece of text with a texture, you need to define that texture—whatever it is—first, and then use it as a fill color on the element of your choice—which, in our case, is a piece of SVG text.

For this example, we will define a linear gradient and use it as a fill for our text.

gradient-text

The code for that looks like this:

<svg xmlns=“http://www.w3.org/2000/svg”  viewBox=“0 0 1250 400” width=“1250” height=“400”> 
    <title>Gradient-filled Text</title>
    <!— Source: http://lea.verou.me/2012/05/text-masking-the-standards-way/ —>
    <defs>
       <linearGradient id=“filler” x=“0%” y=“100%”>
           <stop stop-color=“gold” offset=“0%”></stop>
             <stop stop-color=“purple” offset=“20%”></stop>
           <stop stop-color=“deepPink” offset=“40%”></stop>
           <stop stop-color=“orange” offset=“60%”></stop>
           <stop stop-color=“yellow” offset=“80%”></stop>
           <stop stop-color=“skyblue” offset=“100%”></stop>
      </linearGradient>
    </defs>
    <text x=“100” y=“70%” font-size=“205” fill=“url(#filler)”> Radiant Text</text>
</svg>

Note: we have defined specific height and width for the svg, but to make sure the SVG is responsive, override the default dimensions in CSS and make them percentage-based. You can learn all about making SVGs responsive here.

The <defs> element is used to define our texture—a linearGradient in this case. The gradient gets an ID that is then referenced on our <text> element inside the fill attribute, thus filling the text with the gradient image. Could it get any more semantic?!

Here is a live demo of the above code:

See the Pen Adobe css vs svg text by Sara Soueidan (@SaraSoueidan) on CodePen.

The texture can be anything—even an SVG <image> element that would reference any external image you want (JPEG, PNG, GIF!). It can also be an SVG <pattern>.

And because an SVG is literally a graphic, make sure to include a title so that it’s accessible by screen readers. The title is to the svg what an alt attribute is to an img element in HTML.

 

Applying Texture to Text (Blending with Background)

Similar to the previous technique, combining the concept in the CSS masking section and the definitions inside SVG, we can apply texture to an SVG <text> by first defining the mask we want and then referencing it using the mask attribute (instead of fill).

In this example, I want to apply a bite mark effect to a piece of text that says “nom nom nom”, as shown in the image below.

 

svg-mask-demo

The result of applying an SVG bite marks mask to a piece of text.

 

First I created the bite marks in my graphics editor by drawing them on top of the text that I was going to add the effect to. It helps to do this visually so you make sure that the bite marks end up applied where you expect them to be.

Then, I exported the shapes as SVG and used them to define the shape of the mask inside a <defs> element like so:

<svg viewBox=“0 0 900 400”>
  <defs>
    <mask id=“mask”>
      <rect x=“0” y=“0” width=“100%” height=“100%” fill=“#fff”></rect>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…“></path>
            <path fill=“#000” d=“…“></path>
    </mask>
  </defs>

  <text font-size=“230” fill=“#FF481E” mask=“url(#mask)”>
    <tspan x=“0” y=“150”>nom</tspan>
    <tspan y=“280” x=“150”>nom<tspan>
    <tspan y=“400” x=“350”>nom<tspan>
  </text>
</svg>

There is an important note to remember here: in SVG, unlike in CSS, the element will—by default—be drawn where the mask is white, and it will not be drawn where the mask is black. Any value in between black and white will render the element translucent such that: the closer to white (#ffffff) the color of the masking shape is, the more opaque the shape using the mask will be. The closer the color of the masking shape is to black (#000000), the more transparent the shape using the mask will be.

So, in the above example, I gave the bite shapes a black fill and added a rectangle that fills the entire SVG and coloured it white; this will make sure the text will be fully visible anywhere on the canvas except where the bite marks are in black.

And here is a demo that shows the result of the above code in action:

 

See the Pen adobe css vs svg text by Sara Soueidan (@SaraSoueidan) on CodePen.

And that is all you need to do to apply a texture to text in SVG. You can use a gradient, an image, or any other shape or pattern to mask your text out. And since there are a lot of element options that can go inside that <defs>, you can create some quite interesting effects such as animated textures and fills!…

Animated Text Fills with SVG

Not only does SVG provide us with better support and modularity (because the text and its effect are wrapped inside one image to form our text “graphic”), but the nature of the SVG code allows it to also be animated.

When you define a fill for an element inside <defs>, you can also animate that fill and then, when it is applied to the element, it will still animate as a fill as well. Meaning that effects like the ones in the following image become very much possible:

animated-fills

Animated text fills using SVG.

One of the above example uses a GIF image as a fill (!), so the animated GIF stays animated inside the text it is used to fill as well.

The above examples are all created and explained in this excellent article on Codrops, so make sure you check them out for details including browser support and fallbacks.

Final Words

Until CSS masks are more widely supported and maybe other browsers implement the background-clip: text value, SVG is definitely the best way to create textured text effects on the web.

As a matter of fact, I’d personally still use SVG even if CSS got better for the animation capabilities alone. I also love the fact that the text and its effect are “encapsulated” in one image that can be copied and dropped anywhere, making it more reusable and flexible. And, most importantly, SVG text is fully accessible, searchable, selectable and 100% semantic.

Stay tuned for the next post tackling yet another use case where both CSS and SVG could be used, comparing both and helping you make a better decision which one to choose.

I hope you liked this article and found it useful. Thank you for reading!

Get Started

Free TrialInspired by what you've read? Kick off your next project with Dreamweaver. It's part of Creative Cloud. Download a trial for free!
  • Tyler Sticka says:

    Super cool, Sara! Every post you write makes me more and more excited about SVG. It’s become an essential technology for me, and the results are delightful.

    One remaining pain point I have with styled text via SVG is that several of the paid webfont services (including Typekit) don’t seem to support external SVGs. Any advice on how to take advantage of these nifty features without restricting our typeface selections?

    • Sara Soueidan says:

      Hi Tyler

      Thank you for your comment — so glad you’re enjoying the posts!

      I don’t know if this is what you mean but if you mean applying custom @font-face fonts to an SVG text element then it is definitely possible. You can apply a font-family to SVG text just like you can with HTML text—I did that for an infographic on a recent client project.

      If you mean SVG fonts as in fonts that have a `.svg` format, then those are not really used anymore. They might be back in the future adding the ability to colorize and do some neat things to regular fonts, but not yet.

      I hope that answered your question. Let me know if you have another one.

      Cheers,
      Sara

  • Very cool! There are so many cool things we can do with this. Thanks!

  • I really like your article, your article answered most of my questions about SVG and all the examples were very understandable. Thanks.

  • Hi Sara, what a great post! This is the first post I’ve read that is written by you. I love learning as much as I can on SVG and CSS because it opens so many new doors for me. Your explanations are clear and easy to understand. This is all very cool and clever and I hope you come up with many more new tricks of the trade for me to learn. Thank you!

  • Thanks a lot Sara for being a reliable guide through the dark SVG forest! 🙂
    Another great article as always)

  • Fantastic article! Thanks!

  • Jaspreet Singh says:

    I have 2 few questions
    First, is there any way that it works in Mozilla?
    second, I am trying to capture its screen shot using html5 canvas and other jquery plugin but it takes screen shot of rest of the page except this clipping mask portion.

    Do you know what can be the problem and how i can solve it?

Share your thoughts

Your email address will not be published. Required fields are marked *

*