Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Internet Explorer and tspan vertical alignment

To vertically align a tspan element inside a text element in SVG, the CSS properties alignment-baseline and dominant-baseline work great in Chrome and in FF, respectively. So far so good.

With Internet Explorer it gets a bit crazy:

  • an open bug report asserts that these properties do not work for IE9-11 ...
  • ... but the official documentation states that alignment-baseline is supported
  • CSS feature-sniffing in IE9 & IE11 reports that they support alignment-baseline as well as dominant-baseline for tspan, but they do not work with any values
  • to add confusion to frustration, this MSDN dev page simply says both properties are currently unsupported

This wouldn't be such an issue for IE9 (one could simply hack the desired alignment), but since I want to get away from browser detection, I would like to know:

  • is there a workable cross-browser solution?
  • how come even IE11 doesn't support this basic SVG styling property and how to work around that?

Thanks!

like image 783
cneuro Avatar asked Mar 19 '14 17:03

cneuro


People also ask

What is vertical alignment used for?

The vertical-align property can be used in two contexts: To vertically align an inline element's box inside its containing line box. For example, it could be used to vertically position an image in a line of text. To vertically align the content of a cell in a table.

What is the default vertical alignment?

The default value of vertical-align (if you declare nothing), is baseline. Images will line up with the text at the baseline of the text.

What is used for vertical alignment of the text?

Answer. Answer: The vertical-align CSS property sets vertical alignment of an inline, inline-block or table-cell box.


2 Answers

I have no idea why IE doesn't support alignment-baseline, let alone why you're getting such mixed information.

You can sort of hack the same behaviour using the dy attribute and font-based units ("em" and "ex"). It works pretty well if you just want to center a specific text element on a point.

<text x="50%" y="50%" dy="0.5ex" text-anchor="middle">
    This text will be centered in your coordinate system!
</text>

But the problem with dy is that -- unless y is also set explicitly for the same element -- it is calculated relative to the position of the previous character. So if you want to center a text span relative to the surrounding spans, you have to first adjust for any previous offset and then set the new offset. The resulting code isn't pretty:

<text x="50%" y="25%" font-size="150%">
    <tspan dy="0.5ex">Large font with</tspan><tspan 
        dy="-0.5ex">&nbsp;<tspan
        font-size="50%" dy="0.5ex">small font<tspan
        dy="-0.5ex">&nbsp;</tspan></tspan></tspan><tspan 
    dy="0.5ex">embedded.</tspan>
</text> 
<text x="50%" y="75%" font-size="75%">
    <tspan dy="0.5ex">Small font with</tspan><tspan 
        dy="-0.5ex">&nbsp;<tspan
        font-size="200%" dy="0.5ex">large font<tspan
        dy="-0.5ex">&nbsp;</tspan></tspan></tspan><tspan 
    dy="0.5ex">embedded.</tspan>

http://fiddle.jshell.net/awj49/

Rendering in IE11:

Screen capture of fiddle example
(gray lines mark the reference y coordinate)

If you can, it makes much cleaner code to just explicitly set the y attribute on each tspan:

<text x="50%" font-size="150%">
    <tspan y="25%" dy="0.5ex">Large font with</tspan>
    <tspan font-size="50%" y="25%" dy="0.5ex">small font</tspan>
    <tspan y="25%" dy="0.5ex">embedded.</tspan>
</text> 
<text x="50%" y="75%" font-size="75%">
    <tspan y="75%" dy="0.5ex">Small font with</tspan>
    <tspan font-size="200%" y="75%" dy="0.5ex">large font</tspan>
    <tspan y="75%" dy="0.5ex">embedded.</tspan>
</text>    

http://fiddle.jshell.net/awj49/1/

The final rendering is the same:
Screen capture of second fiddle example

like image 165
AmeliaBR Avatar answered Sep 30 '22 16:09

AmeliaBR


IE doesn't seem to support any vertical alignment CSS properties. A tspan is rendered with a default of what approximates alignment-baseline: central. Therefore, browser detection and polyfilling seems to be the only option just now to have your elements render the same across all browsers.

I adapted AmeliaBR's brilliant answer by manually adding to the y attribute of the parent text element to the desired difference of the font height in pixels (+50% of the font height = hanging, -50% = before-edge ...). Like so:

d3.selectAll('text').each( function() 
    var text = d3.select(this);
    var dy = text.attr('y') || 0;
    var h = text.style('font-size').replace('px', '') * 1;
    var nh = (dy * 1) + (h / 2);
    text.attr('y', nh);
});

I've used d3 here, but obviously this works with any JS library or pure JS DOM-selection.

like image 24
cneuro Avatar answered Sep 30 '22 17:09

cneuro