22

I have two div elements, both with the CSS property display: inline-flex, as I would like to position them beside each other. At first, the div's appear to be positioned properly.

.userImg{
  height: 3em;
  width: 3em;
  background: red;
  display: inline-flex;
}

.nameOfUser{
  display: inline-flex;
  height: 3em; 
  width: 10em; 
  background: blue;
}
<div class = "userImg"></div>
                    
<div class = "nameOfUser"></div>

However, once I place some text inside of the nameOfUser div, it seems to create some strange top margin which makes the two div elements un-aligned from each other.

.userImg{
  height: 3em;
  width: 3em;
  background: red;
  display: inline-flex;
}

.nameOfUser{
  display: inline-flex;
  height: 3em; 
  width: 10em; 
  background: blue;
}
<div class = "userImg"></div>

<div class = "nameOfUser">
  <h3>Jaxon Crosmas</h3>
</div>

Can someone please explain why this is happening and a possible solution?

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Jaxon Crosmas
  • 437
  • 1
  • 4
  • 14

1 Answers1

50

With display: inline-flex you are dealing with inline-level elements.

This activates the vertical-align property, which applies only to inline-level and table-cell elements (source).

The initial value of vertical-align is baseline. This means that inline-level elements position themselves vertically to achieve baseline (text) alignment.

baseline

The baseline is the line upon which most letters sit and below which descenders extend.

enter image description here

Source: Wikipedia.org

This is your current code structure, with the text you added:

.userImg {
  display: inline-flex;
  height: 3em;
  width: 3em;
  background: red;
}

.nameOfUser {
  display: inline-flex;
  height: 3em;
  width: 10em;
  background: aqua;
}
<div class="userImg"></div>
<div class="nameOfUser">
  <h3>Jaxon Crosmas</h3>
</div>

The second element shifts down so that it aligns with the current baseline of the first element.

Now add some text to the first element:

.userImg {
  display: inline-flex;
  height: 3em;
  width: 3em;
  background: red;
}

.nameOfUser {
  display: inline-flex;
  height: 3em;
  width: 10em;
  background: aqua;
}
<div class = "userImg">text</div>
<div class = "nameOfUser">
  <h3>Jaxon Crosmas</h3>
</div>

Notice how the baselines shift to align.

The elements still aren't squarely aligned because the h3 has default vertical margins. If you remove the margins:

.userImg {
  display: inline-flex;
  height: 3em;
  width: 3em;
  background: red;
}

.nameOfUser {
  display: inline-flex;
  height: 3em;
  width: 10em;
  background: aqua;
}

h3 { margin: 0; }
<div class = "userImg">text</div>
<div class = "nameOfUser">
  <h3>Jaxon Crosmas</h3>
</div>

Here are two quick solutions:

1. Override the default value of vertical-align, with any other value.

.userImg {
  display: inline-flex;
  height: 3em;
  width: 3em;
  background: red;
}

.nameOfUser {
  display: inline-flex;
  height: 3em;
  width: 10em;
  background: aqua;
}

div { vertical-align: top; }
<div class = "userImg"></div>
<div class = "nameOfUser">
  <h3>Jaxon Crosmas</h3>
</div>

2. Make the parent a flex container.

This makes your elements flex items, which de-activates vertical-align since flex items are block-level elements.

This method also lines up your elements in a row, because an initial setting of a flex container is flex-direction: row.

.userImg {
  height: 3em;
  width: 3em;
  background: red;
}

.nameOfUser {
  height: 3em;
  width: 10em;
  background: aqua;
}

body { display: flex; }
<div class = "userImg"></div>
<div class = "nameOfUser">
  <h3>Jaxon Crosmas</h3>
</div>
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 2
    Beautifully written answer :) – atwright147 Jul 16 '19 at 11:01
  • Great answer. But there is a mistake, I think. You mentioned that `flex items are block-level elements` and the very spec you linked to literally states: `However, flex items themselves are flex-level boxes, not block-level boxes.` (Below the "example" section in that part of that page) – Arad Alvand Nov 06 '20 at 23:17
  • @Arad, yes, you're correct in citing that section of the spec. But then read the very next paragraph: *"The `display` value of a flex item is blockified: if the specified `display` of an in-flow child of an element generating a flex container is an inline-level value, it computes to its block-level equivalent."* So, at a minimum, there appears to be confusion and contradiction. Honestly, though, I think we're just overlooking the deeply technical definitions of these terms. – Michael Benjamin Oct 12 '22 at 00:16