Easily center text vertically, with SVG!

These days, we have a number of different ways to vertically align text in a container of variable dimensions:

  • Table display modes
  • Flexbox
  • inline-block hacks
  • Wrapping the text in an extra element and absolutely positioning it
  • …and probably many others I’m forgetting

However, often comes a time when neither is suitable, so here I am, adding yet another option to the list. Of course, it comes with its own set of drawbacks, but there are cases where it might be better than the existing solutions.

It all started when I discovered the text-anchor SVG property. It determines where the x and y attributes on <text> elements refer to. The magic starts when you set it to “middle”, then the x and y attributes refer to the center of the text. So, if you set those to 50%, they refer to the center of the SVG graphic itself, and if you set the SVG width and height to 100%, the text basically sits in the center of the <svg>’s container, which could be any HTML element!

One issue was that this centered the baseline of the text, so I tried to find a way to shift the baseline appropriately. Setting dominant-baseline: middle; on the <text> element seemed to fix it, but it looks like IE doesn’t support that. I ended up adding dy=”.3em” to the <text> element, which fixes it but might need to be adjusted if you change the line-height.

In addition, this method has the following drawbacks I can think of:

  • Extra markup (namely 2 elements: <svg> and <text>)
  • If the text is more than one line, it won’t automatically wrap, you have to do it manually.
  • Some new-ish CSS text properties may not be applied. For example, text-shadow is applied in Chrome but not in Firefox, since technically, it’s still not a part of the SVG spec.
  • You need to duplicate the text color as a fill property, since SVG does not understand the color CSS property. No need to duplicate anything, just use fill: currentColor; (thanks GreLI!)

However, it has a few advantages too:

  • You don’t need to change anything on the parent HTML element
  • Degrades gracefully in non-SVG browsers
  • Should be perfectly accessible and won’t break SEO
  • Works perfectly in IE9, unlike Flexbox
  • You can include any kind of SVG styling on the text. For example, strokes!

You can see and play with the result in the dabblet below:

Verified to work in at least Chrome, Firefox, IE9+. Hope it’s useful, even though it won’t be a good fit in every single use case.

  • maxw3st

    Nice technique. Thanks. I’ve been playing around with SVGs and animation, but didn’t realize I could add the text tags inside them.

  • http://www.facebook.com/cleciobachini Clécio Bachini

    Terrific! I’ll try it right now in the www2013 site that we’re developing!

    • http://lea.verou.me/ Lea Verou

      Awesome! I’d love to see it, if it’s private feel free to email me (you can find my email address on the about page). Feel free to ask if you run into any issues.

  • http://twitter.com/Stoikerty .

    I would not even have dreamt of actually using the text and svg elements… very cool. Since you’re there already… let me give you a challenge. Do you think it’s possible to create a replacement for fittextjs with this? (Sorry Trent, Dave and Reagan ;P)
    I’ve been looking at w3c’s svg attributes right now, feels like you just showed me some undiscovered land to explore, thanks :}

  • http://www.facebook.com/markos.giannopoulos Markos Giannopoulos

    Working on mobile and desktop Safari as well :)

  • http://www.developiu.it/ Francesco

    Hi, the idea to use svg is very original! With ie9 support svg is definitely worthy of some study. Still am I wrong or your technique only works for single line texts? This would make simply setting line-height much easier.

    • http://lea.verou.me/ Lea Verou

      It’s much easier for single line texts. I think you could get it to work for multi-line texts, but you need to wrap it manually and adapt the technique a bit.

      • Josh Bambrick

        Fair point but you probably ought to mention that in the article since it is almost always (in my experience) the best solution. Suggesting ‘table display modes, flexbox inline-block hacks, wrapping the text in an extra element and absolutely positioning it’ above just setting the line-height, will send people searching for a solution to this issue down the wrong tracks

  • http://twitter.com/Stoikerty .

    I went in, looked at what I could find and created a fittext.js alternative with pure SVG myself.
    Sure, it’s not perfect, I’m simply assuming that the resizing itself will be proportional.
    But it should work well with a responsive site. I’ve modified your dabblet to suit the needs. Thanks for leading me to this! SVG is wicked.

    http://dabblet.com/gist/5231222

    • http://lea.verou.me/ Lea Verou

      Yay, this looks great! Yes, SVG is wicked indeed. A lot of untapped potential we’re only now starting to discover.

  • http://twitter.com/lmartins Luis Martins

    This is awesome, it only lacks one feature to solve one problem i’ve facing. Would it be possible to resize the text (stil in one line) so it never be bigger than the SVG element?
    As it is now it simply overflows.

  • http://twitter.com/yodirkx Rudie Dirkx

    It doesn’t do multiple line wrapping =( Is that a thing in SVG?

  • http://twitter.com/yodirkx Rudie Dirkx

    My fav vertical align method is with :before http://css-tricks.com/centering-in-the-unknown/

  • http://twitter.com/avenger7x13 Alexey Raspopov

    C’mon guys, this problem is already solved. Why we should create new solutions which create new problem?

    • http://twitter.com/SaggezzaUX Saggezza UX

      innovation breeds change. if people like Lea weren’t trying new solutions we would still be using tabels to layout pages.

  • http://twitter.com/ruGreLI GreLI

    > You need to duplicate the text color as a fill property, since SVG does not understand the color CSS property.

    Actually, you don’t have to duplicate. You can use the “fill: currentColor” rule, and it will inherit a value from the parents ‘color’ attribute.

    • http://lea.verou.me/ Lea Verou

      Thanks, post updated!

      • http://twitter.com/ruGreLI GreLI

        I see the update on Dabblet but not in the post itself. Is it deployed yet?

        • http://lea.verou.me/ Lea Verou

          Odd, I was certain I saved. Did it again, thanks.

        • http://twitter.com/ruGreLI GreLI

          Great! Now it works.

  • Pingback: Easily center text vertically, with SVG!

  • Pingback: Tweet Parade (no.13 Mar 2013) | gonzoblog

  • http://twitter.com/ForbesLindesay Forbes Lindesay

    I’m just directly creating an SVG image and this was super helpful. Thank you for putting it in an article :)

  • http://www.friv10.co/ friv 10

    This is what I’ve been looking for. Thank you!

  • Frank

    Lea like your post too gud

  • Mike Gledhill

    Here’s the JavaScript function I wrote, to do some pseudo-word-wrapping on an SVG text label:
    http://stackoverflow.com/a/17852973/391605

  • http://www.frivjogo.info/ Friv Jogos

    Very useful and supportive article. I wish I can do all of that in a short period of time.

  • Pingback: A Compendium of SVG Information | Lunarium Design

  • Pingback: A Compendium of SVG Information | Vips