Inline SVG increases height of parent element - why and how to prevent it?

Viewed 394

I'm including an svg element in a h1 like this:

<h1>
    64px ABC
    <span class="icon">
        <svg width="64" height="64" viewBox="0 0 64 64">
            <rect id="block" x="4" y="4" width="56" height="56" rx="16" ry="16" stroke-width="1" />
        </svg> 
    </span>
    xyz
</h1>

I then position the icon a little lower to align nicely with the text using relative positioning.

h1 {
    font-size: 64px;
}

.icon {
  position: relative;
  top: 0.14453125em; /* Calculated using https://seek-oss.github.io/capsize/ */
}

svg {
  height: 1em;
  fill: currentColor;
}

This all works, but at a height of 1em, the svg increases the height of it's parent element.

This is the h1 without the svg:

And this is with the svg included:

There's a difference of 5px.

When I change the height to e.g. .9em, this doesn't happen.

I've tried many different options, without the desired result - being to keep the height of the parent element unchanged.

Why does this happen and how can we make sure it doesn't?

CodePen: https://codepen.io/denobelsoftware/pen/MWjKKXO

let iconsHidden = false;
const elements = document.querySelectorAll(".icon");

document.querySelector("#hide-icons").addEventListener('click', function(event) {
  for (var i = 0; i < elements.length; i++) {
    if(iconsHidden){
      elements[i].classList.add('hidden');
    } else elements[i].classList.remove('hidden');
}
  iconsHidden = !iconsHidden;
});
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700&display=swap');

h1 {
    font-size: 64px;
    font-family: 'Roboto', sans-serif;
    font-weight: normal;
    position: relative; /* for the rulers */
}

.icon {
  position: relative;
  top: 0.14453125em;
}

svg {
  height: 1em;
  fill: currentColor;
}

h1:after{
    width: 100%;
    height: 1px;
    content: "";
    position: absolute;
    bottom: 0.244140625em;
    left: 0;
    background-color: rgba(255, 0, 0, 0.23);
    z-index: -100;
}

h1:before{
    width: 100%;
    height: 1px;
    content: "";
    position: absolute;
    bottom: 0.955078125em;
    left: 0;
    background-color: rgba(255, 0, 0, 0.23);
    z-index: -100;
}

.hidden {
  display: none;
}
<body>
    <h1>
        64px ABC
        <span class="icon">
            <svg width="64" height="64" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg">
                <rect id="block" x="4" y="4" width="56" height="56" rx="16" ry="16" stroke-width="1" />
            </svg> 
        </span>
        xyz
    </h1>

    <h1>
        64px ABC
        <span class="icon">
            <svg width="64" height="64" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg">
                <rect id="block" x="4" y="4" width="56" height="56" rx="16" ry="16" stroke-width="1" />
            </svg>
        </span>
        xyz
    </h1>

    <input type="checkbox" id="hide-icons">
    <label for="hide-icons"> Hide icons</label>
</body>

1 Answers

Make the span display:inline-block and add vertical-align:top to avoid the default baseline alignment that will make the linebox bigger then also use line-height:0 to make sure the svg inside will not affect its size. Then you may need to readjust the top value:

@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700&display=swap');

h1 {
    font-size: 64px;
    font-family: 'Roboto', sans-serif;
    font-weight: normal;
    position: relative; /* for the rulers */
}

.icon {
  position: relative;
  top: 0.14453125em;
  display:inline-block;
  vertical-align:top;
  line-height:0;
}

svg {
  height: 1em;
  fill: currentColor;
}

h1:after{
    width: 100%;
    height: 1px;
    content: "";
    position: absolute;
    bottom: 0.244140625em;
    left: 0;
    background-color: rgba(255, 0, 0, 0.23);
    z-index: -100;
}

h1:before{
    width: 100%;
    height: 1px;
    content: "";
    position: absolute;
    bottom: 0.955078125em;
    left: 0;
    background-color: rgba(255, 0, 0, 0.23);
    z-index: -100;
}

.hidden {
  display: none;
}
<body>
    <h1>
        64px ABC
        <span class="icon">
            <svg width="64" height="64" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg">
                <rect id="block" x="4" y="4" width="56" height="56" rx="16" ry="16" stroke-width="1" />
            </svg> 
        </span>
        xyz
    </h1>

    <h1>
        64px ABC

        xyz
    </h1>

    <input type="checkbox" id="hide-icons">
    <label for="hide-icons"> Hide icons</label>
</body>

Related