Create a gist now

Instantly share code, notes, and snippets.

SVG Tips and Tricks (presentation at SVG Summit 2017)

SVG <text>: Tips & Tricks

Notes for a presentation by Amelia Bellamy-Royds
SVG Summit, 15 February 2017

I've set up a CodePen as a scratchpad for the live-coding bits. Don't expect anything there to stay there long; fork the pen if you want to save the code & look at it later.

What is it?

  • Text in SVG
  • Actual text characters included in the markup file, as the text content of DOM nodes
  • Defined by the <text> element
  • Modified by <tspan> and/or <textPath> child elements
  • Shapes of letters from a font
  • Font selection via CSS styles, including @font-face web fonts
  • Color & effects painted like SVG shapes (fill, stroke, filter)
  • Layout via SVG element attributes, SVG-specific CSS styles, and some cross-over styles


What isn't it?

  • SVG graphics shaped like text, but encoded as <path> elements (such as created by "convert text to path" options): this is an image of text, isn't affected by text layout/styles in the browser, and must have alternative text.
    • For inline SVG, alternative could be transparent <text> over top of the paths (best), or alt text from a child <title> element or an aria-label attribute (good for screen-readers & search engines, but no keyboard selection).
    • For SVG as an image, use alt attribute, or use sibling HTML text that is either shifted off-screen or made transparent (best).
  • A replacement for CSS and HTML text layout: there is no browser support yet for auto-wrapping text in SVG, let alone features like bulleted lists or padding & borders around spans.
    • Can use <foreignObject> to embed HTML text blocks in SVG (but no support in Internet Explorer).


Why should you use it?

  • Instead of HTML text:
    • Integrated in an SVG drawing's coordinate system
    • Scales with viewBox
    • Simple, well-supported gradient/pattern-filled text, and text strokes
    • Good browser support for transforms (as attributes), clip-paths, masks & filters
  • Instead of images of text or text as paths:
    • Real text is easy to edit
    • Real text is screen-reader accessible
    • Real text can be selected, copied, translated
    • Real text can be found by in-page search, and by search engines
    • SVG text is infinitely scalable by screen magnifiers & can be styled with currentColor to match high contrast screens (although both of these also apply to text converted to SVG paths)


Why shouldn't you use it?

  • None of the accessibility benefits (relative to SVG paths) come through if SVG is used as an image (<img> or background-image): may as well convert to paths & use HTML for accessible text.
  • Exact layout & appearance depend on fonts: you can use web fonts, but must be willing to accept fallbacks.
  • Creating custom glyph shapes is difficult, with poor browser support. Custom artistic text must still be drawn with <path> (but you can overlay transparent real text to get accessibility & interaction).

But… How?

That's a big question, let's break it down:

Which element do you need?

  • You always need a <text>: <tspan> and <textPath> don't render on their own.
  • <tspan> inside <text> allows you to switch styles and/or re-set layout.
  • <textPath> positions its text along a <path> referenced by xlink:href: curved text, easy angled text
  • When copying & pasting, and for accessibility, browsers treat each <text> as a paragraph, <tspan> and <textPath> are spans.
  • But beware: since they're treated as inline you can't transform a <tspan> or <textPath> (even if they are de-facto absolutely positioned).
  • <a> is also allowed inside <text>: styles can be switched, but not SVG text layout.
    • Link Tip #1: SVG links aren't styled by default; be sure to add your own styles.
    • Link Tip #2: Use xlink:href instead of href for support in Safari & older Chrome/FF.
    • Link Tip #3: You can use a target attribute to open link in another tab, or another <iframe> or <object> in the current page.
    • Link Tip #4: You can use the :target pseudoclass to style elements when you click on a link, and link targets also activate SVG views and SVG/SMIL animation elements.


Where do you want the text?

  • SVG text layout is not CSS text layout! CSS defines boxes & flows text inside. SVG defines anchor points and positions "chunks" of text around them.
  • SVG 1.1 text does not wrap! You set the initial position, and text is laid out like a typewriter until you tell the browser to switch to a different position.
  • Text positions are assigned to characters, not to elements, and can be absolute (x or y) or relative (dx or dy). Each attribute takes a list of values, and inherits into nested elements.
  • An absolute position in the direction of text flow (x for horizontal text) creates an anchor point.
  • "Chunks" are a series of characters starting with the one that has an anchor assigned to it.
  • You can have one anchor for the entire <text>, or an anchor for each character, or anything in between.
  • By default, the chunk is positioned so the baseline of the first character is at the anchor.
  • Change the main alignment with text-anchor: start, middle, or end; effect depends on text direction.
  • Beware: leading/trailing whitespace in a chunk is used in the alignment!
  • Theoretically, you can change the cross alignment with alignment-baseline, dominant-baseline, and baseline-shift: but browser support is a disaster.
  • Instead, use dy to shift text up and down relative to the anchor. (Or dx for vertical text.)
  • Yes, you can do vertical text! But there are two syntaxes: SVG 1.1 vs CSS 3; currently need both for cross-browser support (and there are still bugs & limitations).
  • Add a rotate attribute for even more control, but only recommended if you're absolutely positioning individual characters (or if you want an off-kilter effect).


Where do you want the text, when its on a path:

  • For <textPath>, the position is defined by the linked path: if there's no path, nothing is rendered.
  • The position is as if the <path> was re-drawn in the <text> element's coordinate system. Transforms from the <path> itself apply, but not from its ancestors.
  • Define the initial anchor point using a startOffset attribute; value can be a length or a percent of path length.
    • For text centered on a path, use startOffset="50%" and text-anchor: middle.
    • In theory, create a marquee effect by animating startOffset, but beware a bug in old Chrome and current WebKit.
  • dx, and dy apply to text inside the <textPath>, but:
    • cannot be set on the <textPath> itself, only on parent/child <text> or <tspan>;
    • are treated as offsets along the path or perpendicular to the path, instead of horizontal and vertical.
  • x and y can also be set, but avoid because of cross-browser inconsistencies.
  • FYI: Right-to-left text on a path, and cursive script text on a path are browser support disasters!


What other styles can you control?

  • Familiar CSS-for-text styles

    • Usual CSS styles for selecting font (font, font-family, font-size, font-weight, etc.) and @font-face rules.
    • text-decoration (TIP: use overline underline for a border effect on all-caps text).
    • Theoretically, letter-spacing & word-spacing (but no Firefox support).
    • text-transform in browsers (not officially required by SVG specs).
    • Note: color does not have a direct effect; use fill: currentColor to inherit HTML color and/or to ensure your text will play well with High Contrast mode.
  • Familiar CSS-for-SVG styles

    • fill and stroke, including gradients and patterns
    • paint-order (in latest browsers except Edge)
    • stroke-linejoin, stroke-linecap (though few fonts will have open paths in glyphs)
    • stroke-dasharray and stroke-dashoffset (but no way to identify total path length or control default dash offset)
    • filter, clip-path, mask
  • Direction and writing mode properties

    • direction and unicode-bidi for right-to-left text (with similar effect to HTML attributes).
    • writing-mode and text-orientation for vertical text (use CSS 3 syntax with fallback to SVG 1.1 syntax).
  • Whitespace control

    • white-space, in theory (new in SVG 2); XML xml:space attribute from SVG 1.1 also poorly supported in web browsers.


When should you give up & use HTML or paths?

  • Use HTML (embedded with an SVG <foreignObject> or absolutely positioned on top of the SVG) for:

    • Paragraphs of text
    • Dynamic labels which may need to wrap, unless you're going to add JS code to calculate the wrapping points
    • contenteditable or input elements
    • Custom image icons inline in text
    • Tables or other complex formatting, especially if any text is dynamic
  • Use paths (with alt text) for:

    • Logos or wordmarks where font is essential
    • Distorted or custom glyph shapes not found in the font
    • Stroke-drawing animation to create a hand-written effect

Who should you talk to about bugs & new features?

PS: You can find more examples from the SVG Text Layout book in its supplementary materials, or the text chapter & a few others from the SVG Colors, Patterns & Gradients book or Search my CodePen. The examples from the upcoming Using SVG book will be online soon.

More questions? Want some help amplifying that new bug report you just filed? Ping me on Twitter @AmeliasBrain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment