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
http://blogs.adobe.com/creativecloud/files/2015/07/css-background-clip.png
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:
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.
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 “ 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.
The code for that looks like this:
Radiant Text
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 element is used to _define_ our texture—a `linearGradient` in this case. The gradient gets an ID that is then referenced on our
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 “ element that would reference any external image you want (JPEG, PNG, GIF!). It can also be an SVG .
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 “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.
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 “element like so:
nomnomnom
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 “, 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 “, 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 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!