Search code examples
svgtext-alignmenttspan

Issue with SVG tspans not aligning with text-anchor="end"


I have a bit of code like this:

svg {font-family:Verdana,sans-serif;color:#000;}
.key    {font-size:75%;overflow:visible;}
.caphgh {font-weight:bold;}
.keynor {font-weight:normal;}
.keysub {font-weight:normal;font-size:85%;}
.keyshf,.keyctl,.keyalt     {text-anchor:end;}
.keyshf {fill:#077BC7;} /* CIE-L*ch ( 50, 47,270)   blue    */
.keyctl {fill:#028946;} /* CIE-L*ch ( 50, 55,150)   green   */
.keyalt {fill:#ED0631;} /* CIE-L*ch ( 50, 88, 30)   red */
.yel    {fill:#CEB46C;} /* CIE-L*ch ( 74, 40, 90) */
.non    {fill:none;}
.rec    {stroke:#000;stroke-width:1;}
<svg class="key" x="631.5" y="253.5" width="69" height="69">
    <rect class="rec yel" x="0.5" y="0.5" rx="4" ry="4" width="68" height="68"/>
    <text class="caphgh" x="2.5" y="16.5">K</text>
    <text class="keynor" x="2.5" y="22.5">
        <tspan x="2.5" dy="14">Next</tspan>
        <tspan x="2.5" dy="14">Near</tspan>
        <tspan x="2.5" dy="14">Friend</tspan>
    </text>
    <text class="keysub" y="0.5">
        <tspan class="keyshf" x="68.5" dy="12">Base</tspan>
        <tspan class="keyctl" x="68.5" dy="12">Plant</tspan>
        <tspan class="keyalt" x="68.5" dy="12">Jump</tspan>
    </text>
</svg>

The problem is with the last three tspans. They are all right-aligned, but in Chrome and Firefox the last of the three is closer to the right edge than the first two. In IE 11 this does not happen.

Can anyone tell me what the cause might be? Here is a screenshot:

enter image description here

Thanks!


Solution

  • This is caused by the whitespace in your XML between the <tspan> elements. If we remove that, your problem disappears.

    svg {font-family:Verdana,sans-serif;color:#000;}
    .key    {font-size:75%;overflow:visible;}
    .caphgh {font-weight:bold;}
    .keynor {font-weight:normal;}
    .keysub {font-weight:normal;font-size:85%;}
    .keyshf,.keyctl,.keyalt     {text-anchor:end;}
    .keyshf {fill:#077BC7;} /* CIE-L*ch ( 50, 47,270)   blue    */
    .keyctl {fill:#028946;} /* CIE-L*ch ( 50, 55,150)   green   */
    .keyalt {fill:#ED0631;} /* CIE-L*ch ( 50, 88, 30)   red */
    .yel    {fill:#CEB46C;} /* CIE-L*ch ( 74, 40, 90) */
    .non    {fill:none;}
    .rec    {stroke:#000;stroke-width:1;}
    <svg class="key" x="631.5" y="253.5" width="69" height="69">
        <rect class="rec yel" x="0.5" y="0.5" rx="4" ry="4" width="68" height="68"/>
        <text class="caphgh" x="2.5" y="16.5">K</text>
        <text class="keynor" x="2.5" y="22.5">
            <tspan x="2.5" dy="14">Next</tspan>
            <tspan x="2.5" dy="14">Near</tspan>
            <tspan x="2.5" dy="14">Friend</tspan>
        </text>
        <text class="keysub" y="0.5">
            <tspan class="keyshf" x="68.5" dy="12">Base</tspan><tspan
                   class="keyctl" x="68.5" dy="12">Plant</tspan><tspan
                   class="keyalt" x="68.5" dy="12">Jump</tspan>
        </text>
    </svg>

    It may be a little unintuitive, but when you set text-anchor: end in the <tspan> elements, it covers all the text up until you change the text position. That happens at the next <tspan> element, when you change x and dy. So that extra space in between the spans becomes part of the previous <tspan>. So your first line of text is actually:

    <tspan>Jump</tspan>{spaces}
    

    That's why that text appears to be shifted left by a space.

    Note that the default whitespace behaviour in SVG documents is to collapse consecutive spaces down to a single space.

    You don't really need to be using <tspan> in your example. It would be simpler and cleaner just to use <text> elements.

    svg {font-family:Verdana,sans-serif;color:#000;}
    .key    {font-size:75%;overflow:visible;}
    .caphgh {font-weight:bold;}
    .keynor {font-weight:normal;}
    .keysub {font-weight:normal;font-size:85%;}
    .keyshf,.keyctl,.keyalt     {text-anchor:end;}
    .keyshf {fill:#077BC7;} /* CIE-L*ch ( 50, 47,270)   blue    */
    .keyctl {fill:#028946;} /* CIE-L*ch ( 50, 55,150)   green   */
    .keyalt {fill:#ED0631;} /* CIE-L*ch ( 50, 88, 30)   red */
    .yel    {fill:#CEB46C;} /* CIE-L*ch ( 74, 40, 90) */
    .non    {fill:none;}
    .rec    {stroke:#000;stroke-width:1;}
    <svg class="key" x="631.5" y="253.5" width="69" height="69">
        <rect class="rec yel" x="0.5" y="0.5" rx="4" ry="4" width="68" height="68"/>
        <text class="caphgh" x="2.5" y="16.5">K</text>
    
        <g class="keynor">
            <text x="2.5" y="22.5" dy="14">Next</text>
            <text x="2.5" y="22.5" dy="28">Near</text>
            <text x="2.5" y="22.5" dy="42">Friend</text>
        </g>
    
        <g class="keysub">
            <text class="keyshf" x="68.5" y="0.5" dy="12">Base</text>
            <text class="keyctl" x="68.5" y="0.5" dy="24">Plant</text>
            <text class="keyalt" x="68.5" y="0.5" dy="36">Jump</text>
        </g>
    </svg>