Home > Net >  How to get a flex item to participate in baseline alignment and be centered?
How to get a flex item to participate in baseline alignment and be centered?

Time:09-15

I often run into this issue where there is some extra height coming from somewhere and narrow it down to the baseline of a flex container.

A typical example looks like:

div {
  background-color: #2C3531;
  color: #D9B08C;
}

span {
  background-color: #116466;
}

img {
  width: 40px;
  height: 40px;
}

.container {
  display: inline-flex;
  align-items: center;
}
<div>
  Hello
  <span >
    <img src="https://openclipart.org/image/400px/218125"/>
    World
  </span>
</div>

The problem here is that the baseline of the flex container is the bottom of the image rather than the baseline of "World".

8.5. Flex Container Baselines says:

first/last main-axis baseline set

When the inline axis of the flex container matches its main axis, its baselines are determined as follows:

  1. If any of the flex items on the flex container’s startmost/endmost flex line participate in baseline alignment, the flex container’s first/last main-axis baseline set is generated from the shared alignment baseline of those flex items.

  2. Otherwise, if the flex container has at least one flex item, the flex container’s first/last main-axis baseline set is generated from the alignment baseline of the startmost/endmost flex item. (If that item has no alignment baseline parallel to the flex container’s main axis, then one is first synthesized from its border edges.)

  3. Otherwise, the flex container has no first/last main-axis baseline set, and one is synthesized if needed according to the rules of its alignment context.

In the previous example, I don't think there are any items participating in the baseline alignment since align-items: center. So rule 1 does not apply.

The startmost flex item is the image and so according to rule 2, the baseline is going to be synthesized from the bottom border.

Swapping the text and image around shows the effect of having a different startmost flex item:

div {
  background-color: #2C3531;
  color: #D9B08C;
}

span {
  background-color: #116466;
}

img {
  width: 40px;
  height: 40px;
}

.container {
  display: inline-flex;
  align-items: center;
}
<div>
  Hello
  <span >
    World
    <img src="https://openclipart.org/image/400px/218125"/>
  </span>
</div>

This choice about which flex item the specification says to use seems somewhat arbitrary.

We can make this work by using flex-direction: row-reverse; but that's not a general solution.

div {
  background-color: #2C3531;
  color: #D9B08C;
}

span {
  background-color: #116466;
}

img {
  width: 40px;
  height: 40px;
}

.container {
  display: inline-flex;
  align-items: center;
  flex-direction: row-reverse;
}
<div>
  Hello
  <span >
    World
    <img src="https://openclipart.org/image/400px/218125"/>
  </span>
</div>

The last thing I can think of is to give up on centering using flexbox and use align-items: baseline; line-height: 40px; instead:

div {
  background-color: #2C3531;
  color: #D9B08C;
}

span {
  background-color: #116466;
}

img {
  width: 40px;
  height: 40px;
  align-self: center;
}

.container {
  display: inline-flex;
  align-items: baseline;
  line-height: 40px;
}
<div>
  Hello
  <span >
    <img src="https://openclipart.org/image/400px/218125"/>
    World
  </span>
</div>

While the baseline is right now, the vertical centering is a bit of a hack and requires height matching which is less than ideal.

Are there any other ways to get a flex item to participate in baseline alignment whilst still being aligned via the center?

CodePudding user response:

Adding an empty element at the beginning should work. You can use the ::before pseudo-element for this purpose

div {
  background-color: #2C3531;
  color: #D9B08C;
}

span {
  background-color: #116466;
}

img {
  width: 40px;
  height: 40px;
}

.container {
  display: inline-flex;
  align-items: center;
}
.container::before {
  content: " ";
  white-space: pre;
  width: 0;
}
<div>
  Hello
  <span >
    <img src="https://openclipart.org/image/400px/218125"/>
    World
  </span>
</div>

CodePudding user response:

Add vertical-align: middle; to the container :

div {
  background-color: #2C3531;
  color: #D9B08C;
}

span {
  background-color: #116466;
}

img {
  width: 40px;
  height: 40px;
}

.container {
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
}
<div>
  Hello
  <span >
    <img src="https://openclipart.org/image/400px/218125"/>
    World
  </span>
</div>

  • Related