Right now, my best attempt is this:
html, body { padding: 0; margin: 0 }
.cont
{
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.cont span, .cont input
{
display: inline-block;
}
.cont span
{
box-sizing: border-box;
text-align: right;
background: blue;
flex: 1 0 20rem;
}
@media screen and (max-width: 40rem) {
.cont span { text-align: left; }
}
.cont input
{
background: green;
flex: 1 1 50vw;
box-sizing: border-box;
}
<div class='cont'>
<span>Some Label</span>
<input type="text" value="Text here">
</div>
I did not want to have media queries because there's always the pain to find the breaking point (and this can evolve based on the design changes or device evolutions). Here, I've still used media queries but the 40rem
magic value is computed, not selected by hand.
Typically, one of the form's row item has a fixed size, the other being relative to the viewport size. In this example, the fixed size is 20rem
.
Since they are flex items, they'll wrap when they can't fit anymore on this row, that is when their width will reach their flex-basis
property.
Thus, the width of the row is span_width[20rem] + input_width[50% * w] = 100% * w
I'm deducing that they will wrap when 100% w = 50% w + 20rem => 50%w = 20rem => w = 40rem
So they'll wrap when the viewport's width becomes lower than 40rem
.
The main issue with this is that you must know the exact margin & padding size around such items and this is a real pain to maintain.
Another solution which is not using media queries:
html, body { padding: 0; margin: 0 }
#test
{
display: flex;
align-items: center;
flex-wrap: wrap;
flex-direction: row;
}
#test p
{
flex: 0 1 20rem;
padding:0;
margin:0;
}
#test p s
{
width: calc((48vw - 100%) * 5000);
min-width: 1%;
max-width: 16rem;
display: inline-block;
background: salmon;
height: 1rem;
}
#test p span
{
background: red;
padding-right: 0.5rem;
}
#test b
{
flex: 1 0 50vw;
background: yellow;
}
<div id="test">
<p>
<s></s>
<span>First</span>
</p>
<b>Second</b>
</div>
This works this way:
- The label is split in 2 inline elements, a spacer and the label itself.
- The spacer is using the Fab Four trick, that is, the
width
property is calculated to oscillate between +infinite
and -infinite
in order to be constrained by either min-width
and max-width
.
- The breakpoint is set by the 2nd item in the flex's row (in the example,
window_width:100vw - input_width:50vw
): when the size left for the label is smaller than the minimum width of the row, its max-width
property is used and this adds a "space" push the label element to the right. When the flex row wraps, the size left is now very large and above the breakpoint, and thus the min-width
is selected (in my example, I've used 1%
but it can be 0%
, that is, almost no "margin" on the left of the label).
The caveat of this technic is that you must add a element (could probably be done with a ::before
pseudo element here) and you must set a max-width
less than the parent width - label width
.
That point makes this solution is a pain to maintain.