Home > other >  calc() as SVG coordinate does not re-render when parent width changes
calc() as SVG coordinate does not re-render when parent width changes

Time:02-03

The Issue

In the following HTML code, I'm using the css calc() function to make an SVG line a percentage of the width of the parent container, minus a constant 20px:

<button onclick="myOnClick()">Click me</button>
<div id="my-div">
  <svg xmlns="http://www.w3.org/2000/svg">
    <line
          x1="0px"
          x2="calc(100% - 20px)"
          y1="30px"
          y2="50px"
          stroke="#0000FF"
          strokeWidth="10px"
      />
  </svg>
</div>

When the button is clicked, the width of the parent container is changed.

function myOnClick() {
  document.getElementById("my-div").style.width = "400px";
}

The expected behavior is that the line should change its ending coordinate to take into account the new width of the container. However, the line does not change width.

If you go into the element inspector and then change the x2 of the line to another value, then back to calc(100% - 20px), the line DOES update and takes on the new width of the container. This leads me to believe this is a rendering bug in Chrome.

Other Cases

Curiously, when I change one of the y coordinates to a percentage, rather than a pixel value, it works as expected:

<button onclick="myOnClick()">Click me</button>
<div id="my-div">
  <svg xmlns="http://www.w3.org/2000/svg">
    <line
          x1="0px"
          x2="calc(100% - 20px)"
          y1="30px"
          y2="100%"         <-- LINE CHANGED
          stroke="#0000FF"
          strokeWidth="10px"
      />
  </svg>
</div>

function myOnClick() {
  document.getElementById("my-div").style.width = "400px";
}
#my-div {
  width: 200px;
  height: 500px;
  background-color: red;
  position: relative;
}

svg {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 100%;
}
<button onclick="myOnClick()">Click me</button>
<div id="my-div">
  <svg xmlns="http://www.w3.org/2000/svg">
    <line
          x1="0px"
          x2="calc(100% - 20px)"
          y1="30px"
          y2="100%"
          stroke="#0000FF"
          strokeWidth="10px"
      />
    <line
          x1="0px"
          x2="calc(100% - 20px)"
          y1="30px"
          y2="50px"
          stroke="#0000FF"
          strokeWidth="10px"
      />
  </svg>
</div>

Question

Is this expected behavior, or is this a bug in Chrome that should be reported?

This question only pertains to Chrome, as Firefox and Safari do not seem to support the calc() function for SVG components.

CodePudding user response:

calc() is a CSS function and the x2 attribute is not a presentation attribute (can not be used in CSS) and can only take a length, number or percentage.

What is the width of the SVG was 100% - 20px like in this example:

function myOnClick() {
  document.getElementById("my-div").style.width = "400px";
}
#my-div {
  width: 200px;
  height: 200px;
  border: thin solid black;
  display: flex;
  align-items: flex-end;
  flex-direction: column;
}

svg {
  width: calc(100% - 20px);
  height: 100%;
}
<button onclick="myOnClick()">Click me</button>
<div id="my-div">
  <svg xmlns="http://www.w3.org/2000/svg">
    <line x1="0" y1="30"
          x2="100%" y2="50"
          stroke="#0000FF"
          stroke-width="10" />
  </svg>
</div>

CodePudding user response:

As calc() doesn't work for sg attributes in Firefox or Safari, you could get a similar layout
by applying padding to the parent <svg>

function myOnClick() {
  document.getElementById("my-div").style.width = "400px";
}
#my-div {
  width: 200px;
  height: 500px;
  background-color: red;
  position: relative;
}

svg {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  padding-right: 20px;
}
<button onclick="myOnClick()">Click me</button>
<div id="my-div">
  <svg xmlns="http://www.w3.org/2000/svg">
    
    <line
          x1="0px"
          x2="100%"
          y1="30px"
          y2="100%"
          stroke="#0000FF"
          strokeWidth="10px"
      />
    <line
          x1="0px"
          x2="100%"
          y1="30px"
          y2="50px"
          stroke="#0000FF"
          strokeWidth="10px"
      />
  </svg>
</div>

  • Related