0

If an element has display: inline-flex and contains an <svg> as first child, the element is pushed up.

Use case: A button that can have an <svg> icon as children. Before, after or in the middle of the text.

With flexbox we can align the icon and add spacing between icon and text, regardless of which order they appear in (and without having to wrap the text in <span>).

BUG: However, as you can see, the button that has the icon on the left (i.e. <svg> as first child) is moved up compared to the other two!

button {
  /* This will center align the icon (vertically)
   * and add 5px margin on each side of it */
  display: inline-flex;
  align-items: center;
  grid-gap: 5px;

  font-size: 16px;
  line-height: 20px;
}
<div>
  <button>Text</button>
  <button>
    <svg width="14" height="14" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="50" fill="hotpink" />
    </svg>
    Text
  </button>
  <button>
    Text
    <svg width="14" height="14" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="50" fill="hotpink" />
    </svg>
  </button>
</div>

Without inline-flex to control the layout, the buttons are aligned with each other (but the icons are not center aligned inside the buttons).

button {
  font-size: 16px;
  line-height: 20px;
}
<div>
  <button>Text</button>
  <button>
    <svg width="14" height="14" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="50" fill="hotpink" />
    </svg>
    Text
  </button>
  <button>
    Text
    <svg width="14" height="14" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="50" fill="hotpink" />
    </svg>
  </button>
</div>
ArneHugo
  • 6,051
  • 1
  • 26
  • 47

1 Answers1

1

If you add vertical-align: middle to the parent element, it will fix not be moved up even if it has an <svg> as first child.

button {
  /* This will center align the icon (vertically)
   * and add 5px margin on each side of it */
  display: inline-flex;
  align-items: center;
  grid-gap: 5px;

  /* Align correctly even if the first child is an svg */
  vertical-align: middle;

  font-size: 16px;
  line-height: 20px;
}
<div>
  <button>Text</button>
  <button>
    <svg width="14" height="14" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="50" fill="hotpink" />
    </svg>
    Text
  </button>
  <button>
    Text
    <svg width="14" height="14" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="50" fill="hotpink" />
    </svg>
  </button>
  <button>
    Text
    <svg width="14" height="14" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="50" fill="hotpink" />
    </svg>
    text
  </button>
  <button>
    <svg width="14" height="14" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="50" fill="hotpink" />
    </svg>
    Text
    <svg width="14" height="14" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="50" fill="hotpink" />
    </svg>
  </button>
</div>
ArneHugo
  • 6,051
  • 1
  • 26
  • 47
  • just found your answer and it helped me! but how is this working? i'd be happy to know! – birdy90 Mar 24 '22 at 10:53
  • Is there a particular part of how it works you're wondering about, @birdy90? I've tried to explain the CSS with comments, but let me know if it is confusing. – ArneHugo Mar 24 '22 at 16:41
  • 1
    I meant - why did `vertical-align` helps? It seems, I've already found the solution. That's because inline item align itself by the baseline. It takes button's first child as reference to alignment. If the first is a letter - then letters aligned as intended. But if there is an SVG icon, then button is shifted up, as icon's bottom is lower than the baseline. So `vertical-align` says to ignore it. As long as it is a row of buttons - everything is fine. But if we put a button with icon and label inside some text, we'll see that button label is lower than another text. Thank you for your help! – birdy90 Mar 24 '22 at 18:16