Search code examples
csssvgflexboxvertical-alignment

Flexbox element with <svg> as first child gets mis-aligned upwards


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>


Solution

  • 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>