Without the use of tables or display:table
, is it possible to have a flexible width area for labels to the left of inputs? I would also like to avoid grid layout for browser compatibility reasons. I'd like css to take care of this:
short_label input_box____________________
tiny_label input_box____________________
medium_label input_box____________________
And then also handle larger labels accordingly:
short_label input_box__________
medium_label input_box__________
very_extra_long_label input_box__________
But I do not want:
short_label input_box__________
tiny_label input_box__________
medium_label input_box__________
So the first column needs to have a flexible width, and the second column needs to grow to fill space. My html would ideally look something like this, but if necessary, "row" divs can be added. I feel like there is a flex answer, but maybe not since all the rows needs to be aligned.
<div class='aligned_form'>
<label for='a'>short_label</label>
<input type='text' id='a'>
<label for='b'>medium_label</label>
<input type='text' id='b'>
<label for='c'>very_extra_long_label</label>
<input type='text' id='c'>
</div>
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:
order
propertyThe 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
If you can change the HTML, here's an alternative solution.
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 itemform {
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
I know you said you don't want CSS Grid layout, but I'm going to add it here for documentation purposes. As I think it's the cleanest of the solutions if you don't mind the support problems.
You can always set a fixed width for the inputs by replacing 1fr
with a pixel or other value. Also align-self
is centering the label and inputs vertically, if you'd prefer bottom aligned change center
to end
.
This keeps the HTML super clean too!
.container{
display: grid;
grid-gap: 10px;
grid-template-columns: [label] auto [input] 1fr;
}
input {
grid-column: input;
align-self: center;
}
label {
grid-column: label;
align-self: center;
}
<div class="container">
<label for='a'>short_label</label>
<input type='text' id='a'>
<label for='b'>medium_label</label>
<input type='text' id='b'>
<label for='c'>very_extra_long_label</label>
<input type='text' id='c'>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With