Reputation: 47776
I have some framework generated HTML that I am trying to style.
.row {
display: flex;
flex-direction: row;
}
.field {
display: flex;
flex-direction: column;
}
<div class="row">
<div class="field">
<label>Label</label>
<input type="text">
</div>
<div class="field">
<label>Label<br>over two lines</label>
<input type="text">
</div>
<div class="field">
<label>Label</label>
<input type="text">
<span>error</span>
</div>
</div>
I want the labels, who are always the first child of every field, to be aligned vertically and occupy the same height, as if they were in a table row. However, I cannot change the HTML structure into rows.
I can't just set the alignment to flex-end
because I can have columns with more elements after the label, such as an error message.
Is this possible purely with CSS?
Upvotes: 0
Views: 685
Reputation: 7741
If the structure is always:
In my CSS I used position: absolute
for the span
"immediately after" the input.
Without JavaScript not DRY (No choice), but it is very easy to select and offset each span like this.
.field span:nth-of-type(1){ /* offset value 1 */ }
.field span:nth-of-type(2){ /* offset value 2 */ }
How to align the spans? (One or More)
For example: offset of (n) * 1.5
(For span of 1em font size and 1.5 line height).
.row *{
border: 1px solid lightgray;
}
.row {
display: flex;
flex-direction: row;
}
.row label{
padding-bottom: 4px;
font-weight: bold;
display: block;
}
.row .field {
position: relative;
display: flex;
flex-direction: column;
}
.row input{
background: lightgray;
margin-top: auto;
border: 1px solid black;
}
.row .field span{
position: absolute;
right: 0px;
left: 0px;
/* type */
line-height: 1.5;
font-size: 1rem;
}
.row .field span:nth-of-type(1) {
bottom: -1.5rem;
}
.row .field span:nth-of-type(2) {
bottom: -3rem;
}
[error]{
color: red;
font-style: italic;
}
<div class="row">
<div class="field">
<label>Label</label>
<input placeholder="name" type="text">
<span error>error</span>
</div>
<div class="field">
<label>Label<br>over two lines</label>
<input placeholder="email" type="email">
</div>
<div class="field">
<label>Label<br>over three <br>lines<br></label>
<input placeholder="hello" type="text">
<span error>error</span>
<span>One more error</span>
</div>
</div>
** position absolute could make overlap of items. On Mobile it is better to use position static (Anyway the fields not one next to each other).
input
Without Javascript - Same logic. One way - use *
selector:
input + *{ /* first node after input offset value */ }
input + * + *{ /* second node after input offset value */ }
Upvotes: 1
Reputation: 2261
They are theoretically equal height already. However, flex by default will be flex-start
which means if something like in your case the center label overflows, it will keep all other flex children on the top.
To push them to the bottom instead which will auto align all inputs to the bottom you must set on the parent align-items: flex-end;
which will push all children to the end.
.row {
display: flex;
align-items: flex-end;
gap:5px;
}
.field {
display: flex;
flex-direction: column;
}
UPDATE! Since the original question updated, here's is an updated answer.
If this is the case I would change the field
class to a grid instead of using flex. grid is more flexible for these kind of scenarios.
Change CSS as follows
.row {
display: flex;
flex-direction: row;
}
.field {
display: grid;
grid-template-rows:1fr auto 1fr ;
align-items: flex-end;
}
span {
margin-bottom:auto;
}
Upvotes: 1
Reputation: 144
you can align the row
.row {
align-items: flex-end;
}
or you can try to align the field, like that
.field {
justify-content: flex-end;
}
check both of them.
Upvotes: 1