The possibilities to style, decorate and lay out text in HTML are just awesome! CSS has done an incredible job to make this possible. But if you are familiar with SVG you may still miss two very exciting features.
Stroke and fill text
SVG allows authors to stroke and fill a text. The stroke is the path along a glyph shape that can be styled differently from the shape fill. In the following example the text is stroked with orange.
The following snippet show the SVG code:
<text style="fill: #FFDB80; stroke: #E09F00; stroke-width: 2px;">
Stroke on text
fillproperty is responsible for filling the shape of a glyph.
strokeproperty is responsible for stroking the shape of a glyph.
stroke-widthproperty controls the width of the stroke path.
All major browsers support filling and stroking of SVG text. There is still no CSS module that allows the same for other markup languages.
WebKit implemented the CSS properties
-webkit-text-stroke (shorthand for the two previous properties) to fill this gap. The following snippet styles the text and gives you the same result as in the initial example.
-webkit-text-stroke: #E09F00 2px;
Style text with gradients and patterns
Even WebKit’s CSS properties just allow coloring the stroke and the fill of a text. SVG allows to apply gradients and patterns on a text as well. The first example applies a gradient on the fill and another gradient on the stroke of the text:
<stop stop-color="#FFDB80" offset="0%"/>
<stop stop-color="#FF791F" offset="50%"/>
<stop stop-color="#E09F00" offset="100%"/>
<text style="fill: url(#grad1); stroke: url(#grad2); stroke-width: 2px;">
Gradient on text
The same with patterns and the following image:
<pattern id="pattern1" patternUnits="userSpaceOnUse"
viewBox="0 0 216 78" width="216" height="78">
<image xlink:href="textpattern.png" width="216" height="78"/>
<text style="fill: url(#pattern1);">
Pattern on text
To apply the gradient or the pattern, the
stroke properties use references to the paint resources instead of colors.
fill: url(#pattern1) references the pattern by it’s id.
WebKit implemented another property that allows authors to archive similar effects on HTML text:
-webkit-background-clip: text;. The value
text tells the rendering engine that it should take the containing text of the element and mask it with the background of the same element.
First of all, you need to specify the background of the image. This will either represent a pattern with
background-repeat or a gradient with CSS gradients.
background: url(bgimage.png) repeat;
repeat statement ensures that your image gets repeated if it does not fill the whole background area.
The next step is setting
-webkit-background-clip. Make sure that you use the prefixed version of this property.
The containing text is used as a mask for the background. But the text will still be painted on top of the masked background. To avoid that, the text must be set to transparent.
The transparent text is an accessibility problem for browsers which do not support
-webkit-background-clip: text;. The text won’t be readable there. Instead you just see the unmasked background, filling the size of the whole element. For more details and possible workarounds read Divya Manian’s blog post “Using background clip text with CSS fallback”.
Other tutorials suggest
-webkit-mask instead, which is not less problematic.
A standards conform, interoperable solution – or “yet another hack”
Since all major browsers support SVG, it might make sense to use SVG for this styling purpose. Indeed there is a standards conformant way with full accessibility support as described in the blog post “Text masking — The standards way”.
An SVG element can be used inside your HTML text element, and replaces your text for this element. The text is still there, but encapsulated in the SVG element. The benefit: screen readers and search engines can ignore the SVG code and crawl the text as they did before. In the following snippet, the old code
<h2>Stroke on text</h2>
gets replaced by
<text style="fill: url(#pattern1); stroke: url(#pattern2); stroke-width: 2px;">
Stroke on Text
This is fully functional in Safari, Chrome, Opera and Internet Explorer 9 and up.
Sadly there are several problems with this solution:
- First of all, this only works for text without line breaks. SVG text elements do not support line breaks. Your inline SVG code would get more complicated at the cost of maintainability.
- The SVG element needs a with and height. Everything inside the SVG element gets clipped to it’s dimension. You need to measure each text and set the dimension for each SVG element individually.
h2may not affect the text inside the SVG element. You need to make sure that the SVG element and all of it’s siblings inherit all necessary property values.
- SVG elements contribute to the layout. You need to adjust the layout manually.
A solution for the future
Together with Elika (known as fantasai) from Mozilla and Tab Atkins from Google I tried to find an interoperable solution. Both Elika and Tab run into the same problems.
The proposal we came up with is to allow the
stroke-width properties on text in general. Tab Atkins reached out to the SVG WG to discuss this proposal. The interaction of the
color property to the
stroke properties on text needs to be clarified. This may require changes to
fill and we need to make sure that existing content is not affected. The next step is an official suggestion of the proposal to the CSS WG and ask for approval. Last but not least, the proposal needs to get specified.
There is still a long way to go. But the result will hopefully make decorations of text more powerful than they are already today. Stay tuned!