SVG Text On Path—Part 2

Creating SVG text along a path opens up some interesting and creative possibilities. Last week I showed you the <textPath> element and how to add a reference to a path you define. I also showed you the startOffset attribute so you can position the text somewhere along the path other than the start.

Today I want to talk about two remaining attributes of the <textPath> element and then because last week’s examples all involved straight line paths, I thought I’d show you text on a curved path with a tspan styled differently from the rest of the text. First the two remaining attributes.

If you’d like a reminder about how to create paths in SVG you can read either or both of my posts from a previous SVG series

The method and spacing Attributes

You’re probably not going to use either the method or spacing attributes all that often. They both refine how the text (or spacing) will render on a path and my guess is the defaults will be fine nearly all the time.

Glyphs of certain fonts may not look quite right when displayed on a curved path. The method attribute allows you specify either of two ways that the glyphs should be rendered along a path.

It takes either of two values, align or stretch, with align being the default. A value of align renders glyphs using simple 2×3 transformations in a way that the glyphs neither stretch nor warp. A value of stretch will stretch and possibly warp the glyphs, but depending on the path, might look better.

Unfortunately there doesn’t seem to be much support for the method attribute. I’ve only been able to get examples to work in Opera, which is one reason I suspect you won’t use it much. I also had to experiment to come up with an example where you could see a small difference.

In this example I set the text “SVG Text” on two different curved paths and set the method of the first to stretch and the second to align.

[code type=html]
<svg width="660" height="1000">
<path id="myTextPath" d="M0,0 a1,1 0 0,0 700,0" />

<path id="myTextPath2" d="M0,70 a1,1 0 0,0 700,0" />

<text x="60%" y="0" style="stroke: #000;font-size: 5em;">
<textPath xlink:href="#myTextPath" method="stretch">SVG Text</textPath>

<text x="60%" y="0" style="stroke: #000;font-size: 5em;">
<textPath xlink:href="#myTextPath2" method="align">SVG Text</textPath>

Unless you’re using Opera you won’t notice any difference so instead of a live example, I’ll show you a screenshot captured in Opera.

The method attribute

It’s hard to notice with a quick glance, but if you look closely, you can see the letters along the first path are a little further apart from each other. If you look closer still, you’ll see the letters along the first path are also a little deformed when compared to their counterparts along the second path.

Here are a couple of additional example from Tavmjong Bah’s web site that shows more pronounced changes in the glyphs.

You’ll probably want to leave the default value, align, most of the time, but I’m guessing there are cases where a value of stretch will look better.

The spacing attribute similarly adjusts the text or rather the spacing in the text when rendered along a path. It takes two values, exact and auto, with exact being the default. The value exact tells browsers to render glyphs exactly as specified by the text on a path layout rules, which you can read about if you’re inclined.

I tried hard, but wasn’t able to come up with an example that showed any difference and I was unable to find any searching online. It’s possible that no browsers are currently supporting the spacing attribute at the moment.

Again, I don’t expect you’ll be using either of these any time soon, but I thought they were worth mentioning. Hopefully the example I presented gives you an idea why these two attributes exist, even if they don’t appear to have the support necessary to use them right now.

SVG 2.0 textPath Attributes

SVG 2.0 adds a couple more attributes, d and side. Neither is supported as far as I can tell, but I think both will be easy enough to understand without any examples.

The d attribute is the same d attribute you use to set a path. SVG 2.0 will allow you to set it directly on the <textPath> element if you prefer that to referencing the path.

Here’s one of the textPaths from the previous example that includes the d attribute and removes the xlink:href to reference the path (Again with SVG 2.0 you would use href and not the full xlink:href).

[code type=html]
<text x="60%" y="0" style="stroke: #000;font-size: 5em;">
<textPath d="M0,0 a1,1 0 0,0 700,0">SVG Text</textPath>

If a textPath includes both the d attribute and an href attribute, the latter will be ignored and the path set on d will be the path the text renders along.

The second additional attribute is the side attribute. It will take a value of either left or right and it effectively reverses the path, which you can see in the following screenshot I grabbed from the spec.

SVG 2.0 side attribute

The text on the left uses the value left (the default) and the text on the right uses the value right. You can do the same thing now by altering the paths, but side will be easier to use.

Since I’d rather not wrap up this series with something that doesn’t work, lets look at one more example that does work.

tspans in textPaths

Just as you can with text elements, you can use tspans inside textPaths to position and style a part of the text differently. Here’s an example of text along a curved path that uses a tspan to style one word differently than the rest.

Here’s another reminder about the curve path commands if you need a refresher. In the example I use both M and C commands.

M works the same way as it does for linear paths. C stands for cubic bézier. It takes three coordinates, the first being the control point at the beginning of the curve, the second being the control point at the end of the curve and the third being the ending point for the curve (and the starting point for the next curve).

[code type=html]
<svg width="660" height="220" style="outline: 1px solid red; font-size: 2em; overflow: visible;">

<path id="text-path"
C50,65 150,-65 250,65
C350,165 450,265 550,165
C650,65 650,65 650,65" />

<path id="MyPath" d="M10,165 C 50,65 150,-65 250,65 C 350,165 450,265 550,165 C 650,65 650,65 650,65" fill="none" stroke="#000" stroke-width="2px" />

<text style="stroke: #000;">
<textPath xlink:href="#text-path" startOffset="35%">SVG <tspan fill="red" stroke="red" stroke-width="2px" dy="8">Text</tspan> <tspan dy="-8">on a curved path</tspan></textPath>


The main thing to note here is that I used tspans on the text. I wrapped the word Text in a tspan and styled it to be filled and stroked with red. I then set a dy value of 8 to move the text down a little.

Because this would also move everything after the word “Text” down as well, I wrapped the remaining text in another tspan and set it’s dy to –8 to align its baseline with the path again.

SVG Text on a curved path

I want to call your attention to how the text moved. In last week’s post when talking about startOffset, I mentioned that setting the value of x on the textPath effectively does the same thing as startOffset. It moves the text parallel to the path. Here when setting a value for dy, the text moved perpendicular to the path.

I called this out, because it wasn’t what I initially expected. My expectation was that changes in x or dx would move the text horizontally and y or dy would move it vertically. I was thinking of the movement occurring in the coordinate space of the viewport.

What’s actually happening is the movement occurs in the design space of the EM box around the glyphs, which is aligned parallel and perpendicular to the path.

The following image from the spec shows this.

EM box on a curved path The baseline of the EM box is parallel to the tangent of the curve of the path. I think it helps to think in terms of parallel and perpendicular as opposed to horizontal and vertical when dealing with paths.

Fallback for IE8 and Lower

One last thing I should mention before wrapping up this series is that the textPath element isn’t supported in IE8 and lower. I don’t think that will be a big issue for most of us, but if you have to support older versions of Internet Explorer you can use vector markup language (VML).

The link in the last paragraph will walk you through the details. VML path syntax is similar to SVG path syntax, though you’ll notice the rest of the markup used in the examples is quite different.

Again I don’t expect you’ll need to support IE8 and down, but in case you do there’s a solution for getting text to render along a path.

Closing Thoughts

I hope you agree that using the textPath element allows for some interesting and creative possibilities when displaying SVG text.

Working with textPaths is relatively simple I think. The hardest part is understanding how to create the paths and that just requires a little practice and some experimentation with the values. Referencing the path in the textPath element should be easy enough if you’ve been following along with this series.

That brings us to the end of this series on SVG text. There’s more to talk about in regards to SVG and I’ll return to it again with another series about clipping, masking, and filter effects sometime in the next few months.

It also comes close to bringing us to the end of 2015. Next week I’ll present my “year that was” post for 2015. I’ll remind you of the goals I set for the year and fill you in on how well I did or didn’t do in accomplishing them. The week after will be the first post in 2016 and I’ll talk about the goals I have for the coming year.

Merry Christmas and Happy Holidays.

« »

Download a free sample from my book, Design Fundamentals.

One comment

  1. Great Post !!
    Is there a way to check whether the text is overflown on path or not? I mean if my text does not fit in the path, the excess text is clipped off.
    How can I know whether it is clipped or not?

    • 1. Look at the end of the path.
      2. Compare what you see with the original string.
      3. Determine whether it is clipped or not 😉

Leave a Reply

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