javascripthtmlcss

Element changes size even though width and height are set


In the example below, there is an SVG inside of a "parent" div element. When the SVG is clicked on, a div element "my-div" is prepended to "parent". My expectation was for the SVG to remain the same size and "my-div" to occupy the remaining height inside of "parent". Instead, adding "my-div" causes the SVG to shrink in size. Why does this happen? I have the SVG's width and height attributes set to a specific number. Also, this isn't included in the example, but I tried setting the SVG's width and height CSS styles to 50px each to see if that would resolve the issue, but this didn't help.

This behavior is not specific to SVG elements. I've also tried switching out the SVG for a div element and came across the same behavior.

const circle = document.querySelector('.my-svg')
const parent = document.querySelector('.parent')

circle.addEventListener('click', () => {
  const existing = document.querySelector('.my-div')
  
  if (existing) {
    existing.remove()
  } else {
    const myDiv = document.createElement('div')
    myDiv.setAttribute('class', 'my-div')

    parent.prepend(myDiv)  
  }
})
.parent {
  display: flex;
  flex-direction: column;
  height: 200px;
  position: absolute;
  justify-content: flex-end;
  background-color: yellow; 
}

.my-div {
  width: 100%;
  height: 100%;
  background-color: blue;
}
<div class='parent'>
  <svg width=50 height=50 class='my-svg' viewBox='-20 -20 40 40'>
    <circle r=20 fill='red'></circle>
  </svg>
</div>


Solution

  • You are adding an element with height: 100% to a (column) flex container which defaults to flex-wrap: nowrap so you get a compromise to accommodate both elements on same axis.

    const circle = document.querySelector('.my-svg')
    const parent = document.querySelector('.parent')
    
    circle.addEventListener('click', () => {
      const existing = document.querySelector('.my-div')
    
      if (existing) {
        existing.remove()
      } else {
        const myDiv = document.createElement('div')
        myDiv.setAttribute('class', 'my-div')
    
        parent.prepend(myDiv)
      }
    })
    .parent {
      display: flex;
      flex-direction: column;
      height: 200px;
      position: absolute;
      justify-content: flex-end;
      background-color: yellow;
      flex-wrap: wrap;
    }
    
    .my-div {
      width: 100%;
      height: 100%;
      background-color: blue;
    }
    <div class='parent'>
      <svg width=50 height=50 class='my-svg' viewBox='-20 -20 40 40'>
        <circle r=20 fill='red'></circle>
      </svg>
    </div>

    In order to make the ball div not shrink, there are some flex properties like grow and shrink. In this case, flex-shrink: 0 on the svg would do the trick.

    const circle = document.querySelector('.my-svg')
    const parent = document.querySelector('.parent')
    
    circle.addEventListener('click', () => {
      const existing = document.querySelector('.my-div')
    
      if (existing) {
        existing.remove()
      } else {
        const myDiv = document.createElement('div')
        myDiv.setAttribute('class', 'my-div')
    
        parent.prepend(myDiv)
      }
    })
    .parent {
      display: flex;
      flex-direction: column;
      height: 200px;
      position: absolute;
      justify-content: flex-end;
      background-color: yellow;
    }
    
    .my-div {
      width: 100%;
      height: 100%;
      background-color: blue;
    }
    
    svg {
      flex-shrink: 0;
    }
    <div class='parent'>
      <svg width=50 height=50 class='my-svg' viewBox='-20 -20 40 40'>
        <circle r=20 fill='red'></circle>
      </svg>
    </div>

    UPDATE:

    Does this only happens when you dynamically attach the second div? No, this is irrelevant.

    .parent {
      display: flex;
      flex-direction: column;
      height: 200px;
      position: absolute;
      justify-content: flex-end;
      background-color: yellow;
    }
    
    .my-div {
      width: 100%;
      height: 100%;
      background-color: blue;
    }
    <div class='parent'>
      <div class="my-div"></div>
      <svg width=50 height=50 class='my-svg' viewBox='-20 -20 40 40'>
        <circle r=20 fill='red'></circle>
      </svg>
    </div>