Reputation: 3614
I'm writing a form that's supposed to be responsive, that is, when the browser window is small the left label "jumps" on top (see example below by removing the text-align
property and resizing the browser).
Right now, it works well when the label text is left aligned. For usuabilities issue, I'd like the label to be right aligned (I don't want them too far from the input box) but as soon as the flex has wrapped, I don't want them to be right aligned anymore.
Example code: https://jsfiddle.net/xhtfqbzL/
.cont {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
span
{
flex: 1 0 20vw;
text-align: right;
display: inline-block;
padding-right: 0.5em;
}
input
{
flex: 1 1 20rem;
display: inline-block;
}
<div class='cont'>
<span>Label</span>
<input type="text" placeholder="content">
</div>
So how to achieve this effect ?
Upvotes: 3
Views: 994
Reputation: 3614
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.
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:
width
property is calculated to oscillate between +infinite
and -infinite
in order to be constrained by either min-width
and max-width
.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.
Upvotes: 0
Reputation: 273649
Here is a hack to be used with caution (or not used at all ...)
.cont {
display: flex;
flex-wrap: wrap;
overflow: hidden;
}
.cont:before {
content: "";
flex: 1 0 20vw;
height: 1.2em;
}
span {
flex: 1 1 20rem;
position: relative;
}
span:before,
span:after {
content: attr(data-text);
position: absolute;
padding-right: 0.5em;
}
span:before {
left: 0;
bottom: 100%;
}
span:after {
top: 0;
right: 100%;
}
input {
width: 100%;
}
<div class='cont'>
<span data-text="Label">
<input type="text" placeholder="content">
</span>
</div>
Upvotes: 2