Search code examples
htmlsvg

Safari rending svg text tspan's in wrong positions when using a RTL language


Safari is ignoring positions of tspan's with a svg text when text is a RTL and inverting them.

Here is the fragment:

<svg height="240" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
  <!-- Border -->
  <rect width="120" height="120" style="stroke:pink;fill:white;stroke-width:3;" />
  <path d="M60,5 L60,115 M5,60 L115,60" stroke="pink" />

  <g transform="translate(60,0)">
    <text x="60" y="60" tabindex="0" focusable="true"
      style="fill: rgb(96, 94, 92); font-family: 'Segoe UI', wf_segoe-ui_normal, helvetica, arial, sans-serif; font-size: 12px; text-anchor: middle;">
      <tspan x="0" dy="0">دولة الإمارات العربية</tspan>
      <tspan x="0" dy="20" style="fill: lightsalmon">المتحدة</tspan>
      <title>دولة الإمارات العربية المتحدة</title>
    </text>
  </g>

  <style>
    <![CDATA[
    text {
      font-weight: bold;
    }
    ]]>
  </style>
</svg>

This is how it looks in Chrome and Firefox:

enter image description here

But this is how it looks in Safari:

enter image description here

It seems like Safari is ignoring the dy attribute of the second tspan, and probably positioning first. Is this an issue with Safari's rendering engine or is there something that can be done to fix this?


][3]][3]


Solution

  • State 2023: Obviously, a webkit (core) issue (not specific to safari's webkit implementation)

    I could reproduce this bug in a virtual machine running linux mint with these webkit-based browsers:

    • web/epiphany
    • midori

    A bug you should report:

    Related webkit bug report concerning right-to-left issues:
    "SVG with Hebrew text incorrectly shifted"

    Workaround: insert a left-to-right mark in between the "lines" <tspan>:

    svg {
      height: 20em;
      font-family: sans-serif;
    }
    
    tspan {
      direction: rtl;
    }
    <svg viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
      <rect width="120" height="120" style="stroke:pink;fill:white;stroke-width:3;" />
      <path d="M60,5 L60,115 M5,60 L115,60" stroke="pink" />
        <text x="60" y="60" 
          style="fill: rgb(96, 94, 92); font-family: 'Segoe UI', wf_segoe-ui_normal, helvetica, arial, sans-serif; font-size: 12px; text-anchor: middle;">
          <tspan x="60"  y="60" dy="0">دولة الإمارات العربية</tspan>
          <!-- left-to right mark -->
          <tspan dx="-0.5em" class="br">&#x200E;</tspan>
          <tspan x="60"  dy="20" style="fill: lightsalmon">المتحدة</tspan>
        </text>
    </svg>

    We're actually switching from right-to-left to left-to-right between the pseudo-line <tspan> elements.

    The dx="-0.5em" compensates the introduced extra space (... although, the Right-to-left mark/character shouldn't take any space).

    See also "How do I separate right-to-left text in an SVG without English letters in between?"