align-items: stretch
Flexbox has a feature commonly known as "equal height columns". This feature enables flex items in the same container to all be equal height.
This feature comes from two initial settings:
flex-direction: row
align-items: stretch
With a slight modification, this feature can become "equal width rows".
flex-direction: column
align-items: stretch
Now a column of flex items will have the width of the longest item.
Reference:
align-content: stretch
An initial setting on a flex container is align-content: stretch
. This setting will distribute rows or columns (depending on flex-direction
) across the length of the container.
In this case, in order to pack two columns to the start of the container, we need to override the default with align-content: flex-start
.
References:
flex-direction: column
, flex-wrap: wrap
and height
Since you have a preferred HTML structure (with all form elements logically ordered in one container), flex items will need to wrap in order to form a column of labels and a column of inputs.
So we need to override flex-wrap: nowrap
(the default) with wrap
.
Also, the container must have a fixed height so that items know where to wrap.
References:
The order
property
The order
property is needed to properly align labels and inputs across columns.
Reference:
.aligned_form {
display: flex;
flex-flow: column wrap;
align-content: flex-start;
height: 75px;
}
label[for='a'] { order: -3; }
label[for='b'] { order: -2; }
label[for='c'] { order: -1; }
label, input {
height: 25px;
padding: 5px;
box-sizing: border-box;
}
<!-- No changes to the HTML. -->
<div class='aligned_form'>
<label for='a'>short_label</label>
<input type='text' id='a' placeholder="short_label">
<label for='b'>medium_label</label>
<input type='text' id='b' placeholder="medium_label">
<label for='c'>very_extra_long_label</label>
<input type='text' id='c' placeholder="very_extra_long_label">
</div>
jsFiddle demo 1
Changing the HTML Structure
If you can change the HTML, here's an alternative solution.
- One primary flex container with two flex item columns (labels and inputs)
- Add
flex: 1
to the inputs column so that it consumes all free space in the row and packs the labels column to the width of its longest item
form {
display: flex;
}
form > div {
display: flex;
flex-direction: column;
}
form > div:last-child {
flex: 1;
}
label, input {
height: 25px;
padding: 5px;
box-sizing: border-box;
}
<form>
<div>
<label for='a'>short_label</label>
<label for='b'>medium_label</label>
<label for='c'>very_extra_long_label</label>
</div>
<div>
<input type='text' id='a' placeholder="short_label">
<input type='text' id='b' placeholder="medium_label">
<input type='text' id='c' placeholder="very_extra_long_label">
</div>
</form>
jsFiddle demo 2