Creating large inline forms - css

I have been spending the entire day trying to figure out how I can create big forms and at the same time maintain a proper design of the layout.
Currently I'm using formee (style and 960 grid system), which I have tried to turn into an inline form rather than row based (default). Unfortunately it gets really messy and looks horrible.
To give an visual understanding of what I want to archieve I have created a mockup.
How can I solve issue?

Here is such an example: http://jsfiddle.net/PhilippeVay/gaegv/2/
HTML:
<fieldset class="group">
<legend>First logical group of items</legend>
<div class="col">
<p class="text">
<label for="label1">Field label 1</label>
<input type="text" id="label1" />
</p>
<p class="text">
<label for="label2">Field label 2</label>
<input type="text" id="label2" />
</p>
<p class="text">
<label for="label3">Field label 3</label>
<input type="text" id="label3" />
</p>
</div>
<div class="col">
<p class="text">
<label for="label4">Field label 4</label>
<input type="text" id="label4" />
</p>
<p class="text">
<label for="label5">Field label 5</label>
<input type="text" id="label5" />
</p>
<p class="text">
<label for="label6">Field label 6</label>
<input type="text" id="label6" />
</p>
</div>
</fieldset>
<div class="group fieldset-like">
<p class="textarea">
<label for="label7">Field label 7</label>
<textarea id="label7">some text (test font-size)</textarea>
</p>
</div>
<div class="group">
<fieldset class="col">
<legend>Third legend</legend>
<p class="text">
<label for="label8">Field label 8</label>
<input type="text" id="label8" />
</p>
<p class="text">
<label for="label9">Field label 9</label>
<input type="text" id="label9" />
</p>
<p class="text">
<label for="label10">Field label 10</label>
<input type="text" id="label10" />
</p>
</fieldset>
<fieldset class="col">
<legend>Fourth legend</legend>
<p class="text">
<label for="label11">Field label 11</label>
<input type="text" id="label11" />
</p>
<p class="text">
<label for="label12">Field label 12</label>
<input type="text" id="label12" />
</p>
<p class="text">
<label for="label13">Field label 13</label>
<input type="text" id="label13" />
</p>
</fieldset>
</div>
CSS:
.col {
float: left;
width: 36%;
padding: 2%;
background: #EEE;
}
.col + .col {
margin-left: 10%;
}
.col:after {
content: "";
display: block;
clear: both;
}
fieldset,
.fieldset-like {
margin: 0;
padding: 0;
border: 1px solid darkgreen;
}
.group {
margin: 20px 10px; /* must come after .fieldset-like rule */
}
label {
font-weight: bold;
cursor: pointer;
}
.text { /* because .radio and .checkbox are SO different! */
clear: both;
}
.text label,
.textarea label {
display: inline-block;
width: 39%;
margin-right: 1%;
text-align: right;
background-color: lightgreen;
}
.text input,
.textarea textarea {
display: inline-block;
width: 55%;
border: 1px solid darkgreen;
padding: 4px;
}
.textarea {
width: auto;
padding: 2% 4% 2% 4%;
}
/* label and textarea: also see above */
.textarea label {
width: 14.04%; /* 39% of 36% Yeah I know... */
margin-right: 0.36%; /* 1% of 36% */
background-color: lightgreen;
vertical-align: top; /* otherwise label is at the the bottom of a very high neighbor */
}
.textarea textarea {
width: 74%;
}
a class on paragraph allows to style the label according to the nature of the form element (you can't style a preceding sibling - or a parent - according to an element that comes after it in the DOM, in 2012 and in CSS3 at least ;) ).
you can use selector attributes with modern browsers: input[type="text"] but it's longer to write in a Fiddle AND then you must consider text, password and select element in HTML 4.01 and in HTML5 add email, number, tel, etc That'll multiply the length of your selectors. Or you can use a class on a parent to distinguish and group form elements. Former is needed if you're writing a general reset stylesheet for thousands of colleagues, latter is more efficient if you're also the one writing the HTML code.
.group contains 2 .col, it doesn't matter if it's columns in a fieldset or fieldsets in a div.
calculation of a width into an element having a width means multiplication. Draw it on a sheet of paper and write down each width. It'll allow you to not forget about a single one ;)
padding in percentage doesn't seem to work for input. Not sure about that.
widths on select are easier and cross-browser if you add box-sizing:
select {
-moz-box-sizing: content-box; /* Firefox, meet padding ... */
box-sizing: content-box; /* IE8+ */
padding: 4px 6px; /* example */
}

From a UX standpoint form labels that sit to the left of the field have a lower rate of user completion. The reason for this is that users have to read the label, associate the label to the field and then move their eyes back to the left again after completing filling in of the field. This causes minor eye fatigue and mental distraction.
Forms that have the highest rate of completion is when the label is above the field. The second highest is when the label is within the field. This will also give your form a cleaner look and give the impression to the end user that, even though it might be long. It's not a daunting form to complete.

Related

Add a star after labels when input has 'required' attribute

<div class="form-group">
<label for="Description">"Description"</label>
<input type="text" id="Description" class="form-control"
[(ngModel)]="description" name="Description"
required />
</div>
Is there anyway to add a star (*) after label( label::after) without changing anything in the code by just adding CSS selector? AFAIK there is no support for previous css selector (has) so I cannot use something like:
label:has(+ input:required)::after {
content:" *";
}
No.
Via CSS-only there is no way to achieve the result without changing markup or javascript in the code unless
1) label and input are in the same line, side by side and
2) the background is a solid color
as in the example below, so you could cheat by always adding the star, but if the sibling input is not [required] then cover the star using a box-shadow.
input { border: 1px #ccc solid }
label::after {
content: "*";
width: 1.5em;
margin-right: 1.5em;
}
label + input:not([required]) {
box-shadow: -3.2em 0 0 #fff;
}
<label>Username</label>
<input name='username' required />
<br /><br />
<label>Username</label>
<input name='username' />
But I'd suggest to at least revert the order of the elements in the markup (and showing them in the right order with display:flex and flex-direction: row-reverse)
If you are fine with adding a div around your every label and input group, then below approach can help you.
input {
border: 1px #ccc solid
}
input[required]+label::after {
content: "*";
color: red;
width: 1.5em;
margin-right: 1.5em;
}
.form-group {
display: flex;
}
.form-group label {
order: -1;
width: 100px;
}
<div class="form-group">
<input name='username' required />
<label>Username</label>
</div>
<br /><br />
<div class="form-group">
<input name='username' />
<label>Username</label>
</div>
The correct selector would be
.form-group:has(:required) label
But, alas, as the :has pseudo class is CSS Selectors Level 4 and has no browser support at all.
You can use it with jQuery though:
jQuery($ => {
$('.form-group:has(:required) label').each((i,el) => {console.log(el); el.classList.add('required')})
})
label.required:after {
content: ' *';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="form-group">
<label for="Description"><span>Description</span></label>
<input type="text" id="Description" class="form-control"
name="Description"
required />
</div>
Since you seem to use angular, this might get a little tricky. I don't know, if there is something like this in Angular.

Prevent column-count from breaking elements' border

I'm creating a layout using column-count and -webkit-column-count but I found an issue that appears multiple times.
As you can see from this image, Chrome 45 (not happening in FF) breaks elements' border, which is very strange and quite annoying. This is a bit the code where the break happens (but I don't know why it is not happening here, only difference are fonts, and absence of Mayers css reset):
body {
line-height: 1.5;
}
form {
-webkit-column-count: 2;
column-count: 2;
}
label {
display: block;
-webkit-column-break-inside: avoid;
page-break-inside: avoid;
break-inside: avoid;
margin-top: 0.625em;
}
input {
border: 1px solid green;
border-radius: 4px;
padding: 0.25em 0.5em;
}
label>span:first-child {
width: 5em;
display: inline-block;
}
<h2>CONFIG:</h2>
<form id="pop_values" action="" class="ng-pristine ng-valid">
<label>
<input type="checkbox">
<span>Mobile</span>
</label>
<label>
<input type="checkbox">
<span>Animate</span>
</label>
<label>
<span>Frecuency:</span>
<input type="number">
</label>
<label>
<span>Exclusions:</span>
<input type="text">
</label>
</form>
But it didn't work. Could you give any enlightenment?
Although it is not very clear (without markup) in your question, it seems your form elements (labels and inputs) are not wrapped in their respective containers and are on their own.
You are preventing break on labels only, and hence the inputs are not bound by that rule. This is the reason you are facing that problem.
Best solution would be to wrap your label-input sets in their own containing divs and apply break-inside: avoid on those divs.
Example:
* { box-sizing: border-box; }
form { -webkit-column-count: 2; -moz-column-count: 2; column-count: 2; }
form > div { -webkit-column-break-inside: avoid; page-break-inside: avoid; break-inside: avoid-column; }
form label, form input { display: inline-block; margin: 4px 0px; }
form input[type=text] { width: 50%; }
<form>
<div>
<input id="chk1" type="checkbox" /><label for="chk1">Mobile</label>
</div>
<div>
<input id="chk2" type="checkbox" /><label for="chk2">Animated</label>
</div>
<div>
<label for="txt1">Input 1:</label><input id="txt1" type="text" />
</div>
<div>
<label for="txt2">Input 2:</label><input id="txt2" type="text" />
</div>
<div>
<label for="txt3">Input 3:</label><input id="txt3" type="text" />
</div>
<div>
<label for="txt4">Input 4:</label><input id="txt4" type="text" />
</div>
<div>
<label for="txt5">Input 5:</label><input id="txt5" type="text" />
</div>
<div>
<label for="txt6">Input 6:</label><input id="txt6" type="text" />
</div>
</form>
Fiddle to see the effect of resizing: http://jsfiddle.net/abhitalks/jd7v0n8e/
Note: Last style rule in the above example is to prevent overflow of the inputs when the the available space is less than their default width.
Edit:
(after Op's comment)
Now that you have provided your markup, this arrangement should also work. As long as you are sure that all inputs are properly wrapped inside those labels.
See this snippet:
* { box-sizing: border-box; }
form{
-webkit-column-count: 2;
column-count: 2;
}
label {
display: block; margin: 2px;
-webkit-column-break-inside: avoid;
page-break-inside: avoid;
break-inside: avoid-column;
}
input {
border: 1px solid green;
width: 50%;
}
<form>
<label>This: <input type="text" /></label>
<label>This is long: <input type="text" /></label>
<label>This: <input type="text" /></label>
<label>This: <input type="text" /></label>
<label>This is much longer than before: <input type="text" /></label>
<label>This: <input type="text" /></label>
<label>This: <input type="text" /></label>
<label>This: <input type="text" /></label>
</form>
And also this fiddle: http://jsfiddle.net/abhitalks/38wjpu28/3/
It seems that there must be something else going on in your markup besides what you have shown in your question.
Note 2: I would recommend going with a wrapping div and keeping the label and input separate. This would allow you greater control in case you need to change the layouts later on. (e.g. when you need to put label on top of input instead of side by side)

Align two element rows by second element

I have rows consisting of two elements that I'd like to align by the second element (they're input boxes, and it's nice to have them all line up vertically). The solution I behaves exactly how I want when the elements fit onto one line, I don't want to be using the width of the first element to set the horizontal position. This starts to act weird in small windows or on mobile (when the width of the label is more than 45% of the screen it starts wrapping again).
What would be the proper way to achieve the same result?
FIDDLE
HTML:
<label>Test</label>
<input type="number" value="0">
<br />
<label>Test longer</label>
<input type="number" value="0">
<br />
<label>Test longest text</label>
<input type="number" value="0">
<br />
CSS:
label {
display: inline-block;
float: left;
width: 45%;
text-align: right;
padding: 2px;
margin: 2px;
}
input {
display: inline-block;
float: left;
width: 200px;
padding: 2px;
margin: 2px;
}
You can use flex properties to display rows and columns and remove float
<div class="flex">
<label>Test</label>
<input type="number" value="0">
</div>
<div class="flex">
<label>Test longer</label>
<input type="number" value="0">
</div>
<div class="flex">
<label>Test longest text</label>
<input type="number" value="0">
</div>
in css
.flex {
display:flex;
}
label {
width: 45%;
text-align: right;
padding: 2px;
margin: 2px;
}
input {
width: 200px;
padding: 2px;
margin: 2px;
}
#media(max-width:200px){
.flex{
display:block;
}
}
and use media queries for screen below 200px(or your preference) to make the text and input appear vertically

Aligning submit button and textfields with css

I have a form where I gave the textfields a padding so it will be a bit bigger and nicer. Underneath the form I have a submit button.
The button and the textfields have a width of 100%, but the problem is, is that the button isn't fully 100% by that it isn't equally even in the width with the textfields. What am I doing wrong? Can't seem to "find" the issue
I have put it here http://jsfiddle.net/zrhB6/3/
The Css
input[type=text],input[type=password]{
display: block;
height: 3em;
width: 100%;
}
.btn {
background-color:#c1d82f;
border:3px solid #97a34b;
display:inline-block;
color:#26328c;
font-family:Verdana;
font-size:20px;
font-weight:bold;
padding:6px 24px;
text-decoration:none;
cursor: pointer;
width: 100%;
}
HTML
<div class="grid-container">
<div class="grid-50 login">
<h3>Login</h3>
<form class="grid-100">
<input type="text" name="loginEmail" placeholder="Email"/>
<input type="password" name="loginPassword" placeholder="pass"/>
<input type="submit" name="loginSubmit" class="btn"/>
</div>
<div class="grid-50 login">
<h3>Register</h3>
<form">
<input type="text" name="registerName" placeholder="Name"/>
<input type="text" name="registerEmail" placeholder="Email"/>
<input type="password" name="registerPassword" placeholder="pass"/>
<input type="submit" name="registerSubmit" class="btn"/>
</div>
</div>
I'm using unSemantic grid, but that shouldn't be a issue I think
To both CSS selectors, add:
box-sizing:border-box;
The reason is the default box sizing doesn't include padding and margins in the width, so you're getting 100% + padding + border + margin for the total width.

Forms with multiple columns, no tables

How to position a complex form with multiple fields in line across the screen?
Why are people so hell-bent on avoiding tables?
Tables are not deprecated and should be used when displaying content which logically belongs in a table.
If your form is logically grouped such that a table would be intuitive, please use a table.
Always be thinking: "What's the cleanest, simplest, most maintainable way to achieve this result."
If you want a fluid form with a variable number columns, then disregard this.
I prefer the slightly-more-semantic way, using a definition list:
<dl class="form">
<dt><label for="input1">One:</label></dt>
<dd><input type="text" name="input1" id="input1"></dd>
<dt><label for="input2">Two:</label></dt>
<dd><input type="text" name="input2" id="input2"></dd>
</dl>
Then your CSS:
dl.form {
width:100%;
float:left;
clear:both;
}
dl.form dt {
width:50%;
float:left;
clear:left;
text-align:right;
}
dl.form dd {
width:50%;
float:left;
clear:right;
text-align:left;
}
This should produce a form centered in the page, with the labels in the left column and the inputs in the right
There are many different ways to do this. It's all a matter of preference. What I typically do is have a wrapper div that contains all of the rows, and then a div block per row that contains the label, input, and validator. You can use the line-height CSS property to help you with vertical alignment. Example:
<div class="formWrapper">
<form>
<div class="formItem">
<label for="firstName">First Name:</label>
<input name="firstName" id="firstName" class="required" type="text" />
<span class="validator" style="display: none;">*</>
</div>
... <!-- Rinse repeat -->
</form>
</div>
<style type="text/css">
.formWrapper { width: 400px }
.formWrapper .formItem { line-height: 35px; height: 35px; }
.formWrapper label { width: 50px; }
.formWrapper input { width: 100px; border: 1px solid #000; }
.formWrapper .validator { padding-left: 10px; color: #FF0000; }
</style>
Hope that helps.
After looking at many many different solutions, I found the examples on this page (particularly the one from 'Fatal'?) some of the most helpful. But the extensive and tags did bother me a bit. So here is a little bit of a modification that some may like. Also, you find some sort of 'wrapper' or 'fieldset' style very necessary to keep the float from affecting other HTML. Refer to examples above.
<style>
.formcol{
float: left;
padding: 2px;
}
.formcol label {
font-weight: bold;
display:block;}
</style>
<div class="formcol">
<label for="org">organization</label>
<input type="text" id="org" size="24" name="org" />
</div>
<div class="formcol">
<label for="fax">fax</label>
<input type="text" id="fax" name="fax" size="2" />
</div>
<div class="formcol">
<label for="3">three</label>
<input type="text" id="3" name="3" />
<label for="4">four</label>
<input type="text" id="4" name="4" />
<label for="5">five</label>
<input type="text" id="5" name="5" />
</div>
<div class="formcol">
<label for="6">six</label>
<input type="text" id="6" name="6" />
</div>
That would be done using CSS by setting the "display" property to "inline" (since form elements are, by default, block level elements).
Do a search for "layouts without tables". Many sites describe formatting with CSS. Here is a simple intro: http://www.htmlgoodies.com/beyond/css/article.php/3642151
I suggest you blueprint CSS framework. Have a quick look at the demo page.
This is what I usually use when I need to design pretty complex forms.
HTML:
<fieldset> <legend>Consent group</legend> <form> <fieldset class="nolegend"> <p><label><span>Title</span> <input type="text" name="title" size="40" value="" /></label></p> <p><label><span>Short name</span> <input type="text" name="sname" size="20" value="" /></label></p> <p><label><br /><input type="checkbox" name="approval"> This consent group requires approval</label></p> </fieldset> <fieldset class="nolegend"> <p><label><span>Data use limitations</span> <textarea name="dul" cols="64" rows="4"></textarea></label></p> </fieldset> <input type="submit" value="Submit" /> </form></fieldset>
CSS:
body, input, textarea, select { font: 1em Arial, Helvetica, sans-serif;}input, textarea, select { font-size: .8em }fieldset,fieldset legend { background-color: #EEE;}fieldset { border: none; margin: 0; padding: 0 0 .5em .01em; top: 1.25em; position: relative; margin-bottom: 2em;}fieldset fieldset { margin: 0 0 1em 0;}fieldset legend { padding: .25em .5em 0 .5em; border-bottom: none; font-weight: bold; margin-top: -1.25em; position: relative; *left: -.5em; color: #666;}fieldset form,fieldset .fieldset { margin: 0; padding: 1em .5em 0 .5em; overflow: hidden;}fieldset.nolegend { position: static; margin-bottom: 1em; background-color: transparent; padding: 0; overflow: hidden;}fieldset.nolegend p,fieldset.nolegend div { float: left; margin: 0 1em 0 0;}fieldset.nolegend p:last-child,fieldset.nolegend div:last-child { margin-right: 0;}fieldset.nolegend label>span { display: block;}fieldset.nolegend label span { _display: block;}
I omitted couple lines of CSS with Safari hacks. You can check out live version of this code.
Pace KyleFarris but I just had to give Ben S a vote for having the guts to mention tables. Just look at the variety of CSS solutions on this page and around the internet for a ridiculously simple problem. CSS may one day become a good solution, but for the time being replicating the simple row and column grid that the table tag provides is extremely complex. I have spent countless fruitless hours with this prejudice against tables for things like a form. Why do we do this to ourselves?
input fields, by default, are inline. Therefore, you can simply use line them up without Another option if you want them lined up correctly is as follows:
<div id="col1" style="float: left;>
<input type="text" name="field1" />
<br />
<input type="text" name="field3" />
</div>
<div id="col2" style="float: left;>
<input type="text" name="field2" />
<br />
<input type="text" name="field4" />
</div>
I prefer to use fieldset to group all elements and p for each form field.
<html>
<head>
<style type="text/css">
fieldset {
width: 500px;
background-color: lightblue;
}
fieldset legend {
font-weight: bold;
}
fieldset p {
clear:both;
padding: 5px;
}
fieldset label {
text-align: left;
width: 100px;
float: left;
font-weight: bold;
}
fieldset .Validator {
color: red !important;
font-weight: bold;
}
</style>
<head>
<body>
<form>
<fieldset>
<legend>Data</legend>
<p>
<label for="firstName">First Name:</label>
<input name="firstName" id="firstName" class="required" type="text" />
<span class="Validator" style="display: none;">*</span>
</p>
<p>
<label for="lastName">Last Name:</label>
<input name="lastName" id="lastName" class="required" type="text" />
<span class="Validator">*</span>
</p>
</fieldset>
</form>
</body>
</html>

Resources