Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flexbox align-items: baseline works, but align-self: baseline doesn't. Why?

Tags:

html

css

flexbox

I seem to be observing some confusing behavior with flexbox, specifically when attempting to use align-self: baseline. The basic issue is that it simply doesn’t work; the following snippet demonstrates the problem:

.flex-form {
  display: flex;
}

.flex-form label {
  align-self: baseline;
}

input[type=text] {
  border: 1px solid black;
  font-size: 16px;
  margin: 0 10px;
  padding: 5px;
}

button {
  background-color: white;
  border: 1px solid black;
  margin: 0;
}
<form class="flex-form">
  <label>Label: </label>
  <input type="text" placeholder=" " />
  <button type="submit">Submit</button>
</form>

Here’s a screenshot of what the output looks like:

As you can see, the label’s baseline is not aligned with the other form elements, despite having align-self: baseline set. If I use align-items: baseline on the parent container, however, I get a different result:

.flex-form {
  display: flex;
  align-items: baseline;
}

input[type=text] {
  border: 1px solid black;
  font-size: 16px;
  margin: 0 10px;
  padding: 5px;
}

button {
  align-self: stretch;
  background-color: white;
  border: 1px solid black;
  margin: 0;
}
<form class="flex-form">
  <label>Label: </label>
  <input type="text" placeholder=" " />
  <button type="submit">Submit</button>
</form>

Is this correct behavior according to the spec, or is it a bug? If so, why? Is there a workaround? For reference, I’ve tested on Chrome 54, Safari 9.1.2, and Firefox 50 on macOS 10.11.6, and they all seem to exhibit the same results.

like image 837
Alexis King Avatar asked Nov 21 '16 19:11

Alexis King


1 Answers

Solution

If you want baseline alignment for all items, apply align-self: baseline to each or, more simply, set align-items: baseline on the container.

Explanation

An initial setting of a flex container is align-items: stretch.

This means that all flex items will expand the full cross-axis length of the container.

That's what's happening in your layout. EXCEPT, you've overridden align-items: stretch on one flex item (label), by applying align-self: baseline.

While the other flex items stretch, the label has a baseline instruction – but no point of reference.

From the spec:

8.3. Cross-axis Alignment: the align-items and align-self properties

baseline

If the flex item’s inline axis is the same as the cross axis, this value is identical to flex-start.

Otherwise, it participates in baseline alignment: all participating flex items on the line are aligned such that their baselines align, and the item with the largest distance between its baseline and its cross-start margin edge is placed flush against the cross-start edge of the line.

Okay, let's break this down:

  • The first line doesn't apply. In this case, the flex item's inline axis is the same as the main axis (horizontal), not the cross axis (vertical), so baseline doesn't resolve to flex-start.

  • "...all participating flex items on the line are aligned such that their baselines align..." Well, there's only one item with baseline alignment. There is no other baseline for reference. Apparently, the browser falls back to flex-start in such a scenario (but I haven't seen an official reference for this behavior).

The rest of the spec language is not relevant to this question, but is covered in detail in this related post: What's the difference between flex-start and baseline?

like image 185
Michael Benjamin Avatar answered Oct 11 '22 10:10

Michael Benjamin