Search code examples
csssvg

SVG text grows and overflows on mobile browser


I have a basic SVG element that displays curved text. Although I use a web safe font and relative units in style, the text somehow grows and overflows on mobile browser. I use Chrome 120 both on desktop and Android. I tried other fonts, MS Edge, setting 1rem/16px font-size on root element, they did not help. Why does it happen? How can I fix it?

Desktop Mobile
Desktop enter image description here

Here's the page I use to test:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 480 480">
    <defs>
      <style>
        @import url('https://fonts.googleapis.com/css2?family=PT+Serif:wght@700&display=swap');
      </style>
      <path id="yz" d="M61.92190299775521,240 A178.0780970022448,178.0780970022448 0 0 1 418.0780970022448,240"></path>
    </defs>
    <rect width="100%" height="100%" fill="white" />
    <text style="font-family: 'PT Serif', serif; font-size: 6.9ex; white-space: pre; letter-spacing: -0.05ex;">
      <textPath href="#yz"> LOREM  IPSUM  DOLOR</textPath>
    </text>
  </svg>

Here's a live version of the page: https://gold-gertie-8.tiiny.site/


Solution

  • white-space property applied to svg text is still inconsistently supported across major browsers.

    For a more predictable rendering, try to achieve the layout via SVG startOffset and CSS word-spacing.

    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 480 480">
      <defs>
        <style>
          /*
            @import url('https://fonts.googleapis.com/css2?family=PT+Serif:wght@700&display=swap');
            */
          /* latin */
          @font-face {
            font-family: 'PT Serif';
            font-style: normal;
            font-weight: 700;
            font-display: swap;
            src: url(https://fonts.gstatic.com/s/ptserif/v18/EJRSQgYoZZY2vCFuvAnt66qSVys.woff2) format('woff2');
            unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
          }
        </style>
        <path id="yz" d="M61.9 240a178.1 178.1 0 0 1 356.2 0"></path>
      </defs>
      <rect width="100%" height="100%" fill="white" />
    
      <text style="font-family: 'PT Serif', serif; font-weight:700; font-size: 3.1em; letter-spacing: -0.022em; word-spacing:0.2em">
        <textPath startOffset="2.1%" href="#yz">LOREM IPSUM DOLOR</textPath>
      </text>
    </svg>

    As commented by @Danny '365CSI' Engelman you can also center text on a <textPath> by adding:

    • text-anchor:midde for center alignment
    • startOffset=50% or alternatively specifying a pathLength and a absolute value for the startOffset such as 5 - based on a PathLength of 10.

    However you might need to tweak the startoffset manually to get the visually and typographically most appealing alignment.

    <h3>Text align center (startOffset: 50%)</h3>
    
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 480 480">
      <defs>
        <style>
          /*
            @import url('https://fonts.googleapis.com/css2?family=PT+Serif:wght@700&display=swap');
            */
          /* latin */
          @font-face {
            font-family: 'PT Serif';
            font-style: normal;
            font-weight: 700;
            font-display: swap;
            src: url(https://fonts.gstatic.com/s/ptserif/v18/EJRSQgYoZZY2vCFuvAnt66qSVys.woff2) format('woff2');
            unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
          }
        </style>
        <path id="yz" d="M61.9 240a178.1 178.1 0 0 1 356.2 0"></path>
      </defs>
      <rect width="100%" height="100%" fill="white" />
    
      <text style="font-family: 'PT Serif', serif; font-weight:700; font-size: 3.1em; letter-spacing: -0.022em; word-spacing:0.2em">
        <textPath startOffset="50%" text-anchor="middle" href="#yz">LOREM IPSUM DOLOR</textPath>
      </text>
    </svg>
    
    <h3>Text align center (pathLength:10; startOffset:5)</h3>
    
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 480 480">
      <defs>
        <style>
          /*
            @import url('https://fonts.googleapis.com/css2?family=PT+Serif:wght@700&display=swap');
            */
          /* latin */
          @font-face {
            font-family: 'PT Serif';
            font-style: normal;
            font-weight: 700;
            font-display: swap;
            src: url(https://fonts.gstatic.com/s/ptserif/v18/EJRSQgYoZZY2vCFuvAnt66qSVys.woff2) format('woff2');
            unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
          }
        </style>
        <path id="textPath2" d="M61.9 240a178.1 178.1 0 0 1 356.2 0" pathLength="10"></path>
      </defs>
      <rect width="100%" height="100%" fill="white" />
    
      <text style="font-family: 'PT Serif', serif; font-weight:700; font-size: 3.1em; letter-spacing: -0.022em; word-spacing:0.2em">
        <textPath startOffset="5" text-anchor="middle" href="#textPath2">LOREM IPSUM DOLOR</textPath>
      </text>
    </svg>

    You may also prefer em or better px units at least for svg text. Older browsers might use slightly different calculations and roundings for the relative ex unit.

    Although (usually negligible) you may also force a specific font file by embedding the @font-face rule directly. Google fonts applies a lot of browser sniffing - thus an iOS safari will retrieve a slightly different font version.