sontek sontek - 4 months ago 18
CSS Question

How to align icons in a form using flexbox / css in a responsive way

I'm designing a form using flexbox so that it can be responsive on desktop and mobile. Here is a demo of what I have so far:

http://codepen.io/sontek/pen/akQqYN?editors=1100

CSS:

@import 'https://fonts.googleapis.com/css?family=Roboto:300,400,500';
@import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css);

body {
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
}

.control .input {
color: #5f5f5f;
box-sizing: border-box;
width: 60%;
box-shadow: 1px 2px 4px 0 rgba(0, 0, 0, 0.08);
padding: 15px;
border: 1px solid #dbdbdb;
display: inline-flex;
}

.control.success .input {
border: 1px solid #4EA822;
}

.control.success i {
color: #4EA822;
}

.control.error .input {
border: 1px solid rgba(237,108,99, 0.7);
}

.control.error i {
color: #ed6c63;
}

.control {
margin-bottom: 10px;
min-width: 300px;
width: 100%;
}

.control .help {
margin-top: 10px;
color: #999;
font-size: 0.9em;

@media (min-width: 600px) {
text-align: right;
}

}

.control .row {
display: flex;
flex-direction: column;

@media (min-width: 600px) {
align-items: center;
justify-content: center;
flex-direction: row;
}
}


.control .label {
font-size: 1.2em;
color: #555;
@media (min-width: 600px) {
text-align: right;
}
padding-right: 10px;
}

.control .row {
.label {
flex: 1;
}
.input {
flex: 2;
padding-right: 30px;
padding-left: 30px;
width: 100%;
}

i {
width: 0;
display: inline-flex;
position: relative;
left: -25px;
}
}

.control i {
font-size: 20px;
}

.center-block {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 20px;
}


HTML:

<form class="center-block">
<div class="control">
<div class="row">
<label class="label">Standard</label>
<input type="text" name="text-input" class="input"/>
</div>
<div class="help">
Help Information
</div>
</div>
<div class="control success">
<div class="row">
<label class="label">Success</label>
<input type="text" name="text-input" class="input"/>
<i class="fa fa-check"></i>
</div>
<div class="help">
Help Information
</div>
</div>
<div class="control error">
<div class="row">
<label class="label">Error</label>
<input type="text" name="text-input" class="input"/>
<i class="fa fa-warning"></i>
</div>
<div class="help">
Help Information
</div>
</div>
</form>


The problem right now is that when its responsive on mobile and flips to column direction in the flow the icons drop blew:

enter image description here

EDIT The above screenshot doesn't reflect the codepen, I was able to get the icon aligned on the left side of the textbox for mobile but I'd prefer having it on the right side of the textbox.

EDIT 2: I've fixed the icons. Just need to fix the whitespace problem now.

I'd like it to stay within the input when its row and when its column.

The other big issue I have is with spacing on the labels, I'd like to label to only flex enough to be as wide as the widest label and let the input take over the rest of the space, that way they are aligned properly.

This whitespace is unnecessary:

enter image description here

Answer

The icons are shifting to the bottom because on smaller screens you're shifting the container to flex-direction: column. Hence, the label, input and icon (all flex items), will stack vertically.

Instead, for smaller screens, keep the container in flex-direction: row, add flex-wrap: wrap and give the label a 100% width. This will force the input and icon to the next line.

/* .control .row { flex-direction: column; }  */
.control .row { flex-wrap: wrap; }
.control .label { flex: 0 0 100%; } 

To fix the white space issue on the left, try this:

@media (min-width: 600px)
.control .row .label {
    /* flex: 1; */
    flex: 1 0 10%;
    white-space: nowrap; 
}

.control .row .input {
    flex: 2;
    padding-right: 30px;
    padding-left: 30px;
    /* width: 100%; */
}

Now, the text-align rule in your code will position the label within the width limitation applied (10% in my example).