Search code examples
svg

How to use calculated width for SVG rect?


I was trying to develop a svg skeleton image for showing it while data is loading, here is code which I was using for editing svg.

// converting svg tag to data url and setting it as background image
const svgURL = 'data:image/svg+xml;charset=utf-8;base64,' + btoa(document.querySelector('svg').outerHTML);
document.querySelector('#xyz').style.backgroundImage = `url(${svgURL})`;
svg {
  height: 48px;
}
.xyz {
  background-repeat: repeat-y !important;
  background-size: 100% 48px !important;
}
<svg
  width="100%"
  height="48"
  xmlns="http://www.w3.org/2000/svg"
  stroke="none"
  fill="grey"
>
  <circle cx="24" cy="24" r="12" />
  <rect height="20" width="calc(100% - 60px)" x="48" y="14" rx="10" ry="7" fill="grey" />
</svg>

<div id="xyz" style="border: red 1px solid; height: 300px; width: 100%"></div>

As you can see same svg is rendered correctly if it is part of html, but as soon as we use it as background, width of rectangle is not setting correctly.

Any idea what I am doing wrong and how we can fix it?


Solution

  • CSS calc() can still be unpredictable across different browsers when applied to SVG elements.

    You may use this hack using <line> elements instead of <rect>.
    We're defining a length via x2=100%,
    apply a translateX transformation to shorten the line to the right
    and a left x offset.

    Tested in Firefox, Chrome and Safari.

    // converting svg tag to data url and setting it as background image
    const svgURL = 'data:image/svg+xml;charset=utf-8;base64,' + btoa(document.querySelector('svg').outerHTML);
    document.querySelector('#xyz').style.backgroundImage = `url(${svgURL})`;
    svg {
      height: 48px;
      border:1px solid #ccc;
    }
    .xyz {
      background-repeat: repeat-y;
      background-size: 100% 48px !important;
      resize:both;
      overflow:auto;
      
    }
    <svg
      width="100%"
      height="48"
      xmlns="http://www.w3.org/2000/svg"
      stroke="none"
      fill="grey"
    >
      <circle cx="24" cy="24" r="12" />
      <line x1="110" y1="24" x2="100%" y2="24" stroke-width="20" stroke-linecap="round" stroke="grey" style="transform:translate(-40px, 0)"></line>
    </svg>
    
    <h3>Resize me</h3>
    <div class="xyz" id="xyz" style="border: red 1px solid; height: 300px; width: 100%"></div>