Using SVG with CSS3 and HTML5 — Supplementary Material

Example code and online extras for the O'Reilly Media book by Amelia Bellamy-Royds, Kurt Cagle, and Dudley Storey.

Beyond Horizontal: Rotated and Vertical Text

SVG text is designed for decorative layouts, allowing you to position individual characters exactly where you want them. We showed in the book how you can shift individual characters in the x and y dimensions, with attributes on the containing element.

The final option for character positioning is the rotate attribute, allowing you to set the angle of those characters.

Like x, y, dx, and dy, the rotate attribute takes a list of values which are assigned, one-by-one, to the characters in the text content. The last value in the list affects all remaining characters in the current element—but, unlike with the positioning attributes, the rotation doesn’t persist for characters after the element’s end tag.

The values in rotate are measured in degrees, but are given as numbers without units. Positive numbers are clockwise rotation, negative numbers are counter-clockwise.


Each rotation value is absolute, relative to normal layout, regardless of the previous value.

Each character is rotated relative to its own origin, rather than around the center of the glyph: this is normally the point at the “start” side of the baseline of the text. The rotations are applied after the rest of layout, and spacing of letters isn’t adjusted to fit. These details mean that rotate is best used in combination with exact character placement with the other positioning attributes—don’t expect the browser to automatically create typographically-pleasing results with rotated characters.

To create more elegant rotated text, you can use <textPath> (which we discuss in the book and in the “Perfecting Paths for <textPath>” article) to curve or angle a continuous line of text.

For vertical or sideways text, the writing-mode property is a better option—although current browser implementations are not guaranteed to result in perfect typography, either.

Nonetheless, rotate can be very effective at creating layouts that convey a sense of complete disorder, as done in Example 7-X2 (with the results in Figure 7-X2) to visualize a screaming voice falling out of control. In this case, we’re taking a vertical line of text and rotating each character by 15° more than the character before it, so that the letters flip around a full turn by the time they reach the bottom.

A tall vertical comic book speech bubble. The text 'Aaaaaaaaaaaaaaaaahhh!!!!' is written from top to bottom, letters successively twisting around sideways, upside-down, then back upright again. Letters also get smaller as it goes, with the final exclamation points each getting larger again.
Figure 7-X2. Rotated letters in SVG comic book text (view live SVG file, including linked @font-face font)
Example 7-X2. Using rotate to alter the angle of individual characters
<svg xmlns="" xml:lang="en"
     viewBox="0 0 200 500">
    <title>Scream—Comic Book text</title>
@font-face {
    font-family: 'SequentialistBB';
    src: url('fonts/SequentialistBB.woff2') format('woff2'),
         url('fonts/SequentialistBB.woff') format('woff');
    font-style: normal;
    font-weight: 400;
}                                                          1
text {
    font-family: SequentialistBB,
                 Papyrus-condensed, Impact,
                 sans-serif-condensed, sans-serif;
    font-stretch: condensed;
    writing-mode: tb;           /* SVG 1 syntax */
    glyph-orientation-vertical: 0;                         2
    writing-mode: vertical-rl;  /* CSS3 syntax */
    text-orientation: upright;
    font-size: 28px;
tspan { font-size: 75%; }                                  3
path {
    fill: #fff;
    stroke: #000;
    stroke-width: 2;
    <path d="M175,495 L140,465 C30,500 40,400 30,200
             S70,10 100,10 S170,0 170,200 S170,400 150,450 Z" />
    <text x="100" y="12"
          rotate="0 15 30 45 60 75 90 105 120 135 150 165 180
                  195 210 225 240 255 270 285 300 315 330 345 360"
          textLength="450">                                4
          >!</tspan>!</tspan>!</text>                      5

The @font-face rule is the same as previous examples in the book, as are the font styles designed to ensure that a similarly-proportioned fallback font will be used if the web font doesn’t load.


The vertical layout is defined with the writing-mode and orientation properties: first, with the old SVG 1 syntax, and then with the new CSS3 syntax.


As part of the “falling” layout, the text will get progressively smaller, using nested <tspan> elements, each set to a font-size that is 75% of its parent’s size.


The remaining aspects of the layout are defined by attributes on the <text> element itself: the rotate attribute lists different angles for each character, while the textLength attribute sets the overall length of the text to fit within the speech-bubble path.


The nested <tspan> elements break up the stream of letters, with the final exclamation marks breaking out of the nested layers—and therefore each being larger than the last, back to the original font-size.

We’ve mentioned vertical text before, but haven’t discussed it in full. It is only recently getting to the point of good browser support. Results are still somewhat buggy and inconsistent in web browsers (at the time of writing). However, it can be used for decorative effects like this where you’re not too worried about exact layout and perfect typography.

There are two syntaxes which can be combined to get almost-complete browser support for vertical writing modes:

SVG 1.1 vertical text
  • uses writing-mode property with value tb to create vertical (top-to-bottom) lines of text;

  • uses glyph-orientation-vertical property to set the type of vertical text layout, set to one of these values:

    • 0 for always upright (un-rotated) characters, stacked one under the other,

    • 90 to have the entire line rotated sideways, 90° clockwise,

    • auto (the default) to have sideways text for normally-horizontal scripts, but upright characters for scripts (like Chinese and Japanese) for which this is a standard writing style;

  • is fully supported in WebKit and Blink; Internet Explorer & Edge support writing-mode but not glyph orientation control; older Firefox had no support, but the latest Firefox versions now support writing-mode: tb as a synonym for CSS 3 writing modes.

CSS 3 vertical text
  • uses writing-mode property to set vertical text and line-wrapping direction, using one of these values:

    • vertical-rl for vertical text that wraps so that the first line of a paragraph is on the right (this is standard for Japanese and Chinese vertical text),

    • vertical-lr for vertical text that wraps so that the first line of a paragraph is on the left;

  • uses text-orientation property to set the type of vertical text:

    • mixed (the default, and the same as glyph-orientation-vertical: auto),

    • upright for un-rotated characters,

    • sideways for sideways text rotated clockwise;

  • is currently (mid-2017) only supported in Firefox and Chrome/Blink, but is expected to be adopted everwhere eventually.

Example 7-X2 uses both syntaxes, relying on the CSS parser to let the new values override the old in supporting browsers. The double declarations provide full support for Blink, WebKit, and Firefox versions from 2016 and later, and partial support in IE and Edge.


In IE and Edge, the text will be laid out sideways before rotate is applied, so each letter will be rotated an additional 90°.

Sideways text takes up a lot less vertical space than upright vertical text. And even among browsers that support upright vertical text, there is a lot of variation in how they space out the letters. The Sequentialist BB web font, like most fonts for normally-horizontal scripts, doesn’t include suggested vertical spacing in the font data.

To make sure the text fits the speech bubble in all these cases, and also with fallback fonts, we’ve used another new attribute: textLength. The textLength defines the exact total length that the text should cover. The browser then adjusts the spacing between characters to make it fit.

textLength is a regular XML attribute, not a style property that can be set in CSS. It’s value is always a number, representing a distance in SVG user units (px units).


Browsers are all a little inconsistent about how they handle textLength values when there are <tspan> elements nested inside <text> elements. Test carefully, and don’t use the attribute if you don’t have to.

The textLength value means that we don’t have to worry about changing the text-anchor to have a better fallback experience: we know exactly where the start, middle, and end of the text will be positioned because it will always have the same total length. But for other cases, it’s worth repeating: for vertical text, text-anchor defines the vertical alignment, relative to the y position of the text chunk.