CodePen

HTML

            
              <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/> -->

<h1><span>Best Practice</span> Forms</h1>
<h2>This example meets following requirements</h2>
<ul>
  <li>Container independent, flexible widths in percent</li>
  <li>Responsive, linearizable, mobile-ready</li>
  <li>Browser support: IE8 and up, Chrome latest, Safari latest, Firefox latest, Opera latest, major mobile browsers</li>
  <li>2 variants: labels left (for most forms) and labels above (small or narrow forms)</li>
  <li>Doesn't break with multi-line labels</li>
  <li>Client-side validation via HTML5 input types and JavaScript support</li>
  <li>Inline error messages</li>
  <li>Backend/templating friendly
    <ul>
      <li>Suitable for using label/input/error includes/snippets</li>
      <li>Slim and flexible markup</li>
    </ul>
  </li>
</ul>
<form action="#" method="get">
  <fieldset class="wideform">
    <h3 class="legend">Form kitchen sink</h3>
    <p><b>Labels left:</b> Suitable for most forms<br/>
      <b>Labels above:</b> Better for short or narrow forms</p>
    <a href="javascript://" class="primary button js_toggleLabelPosition">Switch label position</a>
    
    <hr/>
    
    <div class="formrow">
      <div class="formitem">
        <div class="label req">Salutation</div>
        <div class="ticks">
          <label>
            <input type="radio" name="salutation" value="mrs" required="required"/>
            <span>Mrs.</span>
          </label>
          <label>
            <input type="radio" name="salutation" value="mr" required="required"/>
            <span>Mr.</span>
          </label>
          <label>
            <input type="radio" name="salutation" value="miss" required="required"/>
            <span>Miss</span>
          </label>
          <label>
            <input type="radio" name="salutation" value="jack" required="required"/>
            <span>Jack</span>
          </label>
          <label>
            <input type="radio" name="salutation" value="queen" required="required"/>
            <span>Queen</span>
          </label>
          <label>
            <input type="radio" name="salutation" value="king" required="required"/>
            <span>King</span>
          </label>
          <label>
            <input type="radio" name="salutation" value="sir" required="required"/>
            <span>Sir</span>
          </label>
          <label>
            <input type="radio" name="salutation" value="lord" required="required"/>
            <span>Lord</span>
          </label>
          <label>
            <input type="radio" name="salutation" value="master" required="required"/>
            <span>Master</span>
          </label>
          <label>
            <input type="radio" name="salutation" value="president" required="required"/>
            <span>President</span>
          </label>
        </div>
      </div>
    </div>
    <div class="formrow">
      <label class="label req" for="firstname">First/last name</label>
      <div class="formitem col1of2">
        <label class="label req" for="firstname">First name</label>
        <input type="text" name="firstname" id="firstname" placeholder="Placeholder" required="required" x-autocompletetype="given-name"/>
      </div>
      <div class="formitem col1of2">
        <label class="label req" for="firstname">Last name</label>
        <input type="text" name="lastname" id="lastname" placeholder="... with polyfill" required="required" x-autocompletetype="family-name"/>
      </div>
    </div>
    <div class="formrow">
      <div class="formitem col1of3">
        <label class="label" for="zip">Zip</label>
        <input type="text" name="zip" id="zip" pattern="[0-9]{5}" x-autocompletetype="postal-code"/>
      </div>
      <div class="formitem col2of3">
        <label class="label" for="zip">City</label>
        <input type="text" name="city" id="city" x-autocompletetype="city"/>
      </div>
    </div>
    <div class="formrow">
      <div class="formitem col1of2">
        <label class="label" for="email">Email</label>
        <input type="email" name="email" id="email" x-autocompletetype="email"/>
      </div>
      <div class="formitem col1of2">
        <label class="label" for="phone">Phone... Some more text for testing super long labels. It will happen, clients will do that. Lorem ipsum dolor sit amet, consectetuer adipiscing elit...</label>
        <input type="tel" name="phone" id="phone" x-autocompletetype="tel"/>
      </div>
    </div>
    <div class="formrow">
      <div class="formitem col1of2">
        <label class="label" for="website">Your website, blog, Ihr Google Plus, Twitter or Facebook profile, whatever. Lots of text for testing really long labels, you know...</label>
        <input type="url" name="website" id="website" x-autocompletetype="url"/>
      </div>
      <div class="formitem col1of2">
        <a href="javascript://" class="button">Link button</a>
        <button type="button" class="button disabled" disabled="disabled">Disabled button</button>
      </div>
    </div>
    <div class="formrow">
      <div class="formitem col1of2">
        <label class="label" for="password">Password</label>
        <input type="password" placeholder="Password" name="password" id="password"/>
      </div>
      <div class="formitem col1of2">
        <input type="password" placeholder="Password again" name="passwordagain" id="passwordagain"/>
      </div>
    </div>
    <div class="formrow">
      <div class="formitem">
        <label class="label req" for="message">Message</label>
        <textarea name="message" id="message" cols="40" rows="5" required="required"></textarea>
      </div>
    </div>
    <div class="formrow">
      <div class="formitem">
        <div class="label req">Your rating</div>
        <div class="rating">
          <input type="radio" name="rating" value="5" id="rating5" required="required"/>
          <label for="rating5" class="star">
            <span>5 stars</span>
          </label>
          <input type="radio" name="rating" value="4" id="rating4" required="required"/>
          <label for="rating4" class="star">
            <span>4 stars</span>
          </label>
          <input type="radio" name="rating" value="3" id="rating3" required="required"/>
          <label for="rating3" class="star">
            <span>3 stars</span>
          </label>
          <input type="radio" name="rating" value="2" id="rating2" required="required"/>
          <label for="rating2" class="star">
            <span>2 stars</span>
          </label>
          <input type="radio" name="rating" value="1" id="rating1" required="required"/>
          <label for="rating1" class="star">
            <span>1 star</span>
          </label>
        </div>
      </div>
    </div>
    <div class="formrow">
      <div class="formitem col1of2">
        <label class="label" for="country">Country</label>
        <select name="country" id="country" x-autocompletetype="country-name">
          <option selected="selected">please choose</option>
          <option>U.S.A.</option>
          <option>France</option>
          <option>Italy</option>
          <option>Spain</option>
          <option>Germany</option>
        </select>
      </div>
    </div>
    <div class="formrow">
      <div class="formitem">
        <div class="ticks">
          <label>
            <input type="checkbox" name="terms" class="error" required="required"/>
            <span>Yes, of course I agree to your monstrous <a href="javascript://">terms and conditions</a> and I allow every possible and impossible use of the data I will ever provide you with. This checkbox has an error class preset to simulate backend-side validation. And the text is looong so it makes a great click target and won't ever be read completely.</span>
          </label>
        </div>
        <label for="terms" class="error">Please agree to our terms of service to proceed.</label>
      </div>
    </div>
  </fieldset>
  
  <div class="buttons">
    <div class="forth">
      <input type="reset" value="Reset" class="button"/>
      <button class="primary button">Submit</button>
    </div>
    <div class="back">
      <button class="button" name="back">Back</button>
      <a href="javascript://">Text aligns nicely</a>
    </div>
  </div>
</form>
            
          
!

CSS

            
              @charset "UTF-8";

@font-face {
	font-family: 'FontAwesome';
	src: url('http://cdnjs.cloudflare.com/ajax/libs/font-awesome/3.0.2/font/fontawesome-webfont.eot?v=3.0.1');
	src: url('http://cdnjs.cloudflare.com/ajax/libs/font-awesome/3.0.2/font/fontawesome-webfont.eot?#iefix&v=3.0.1') format('embedded-opentype'),
		url('http://cdnjs.cloudflare.com/ajax/libs/font-awesome/3.0.2/font/fontawesome-webfont.woff?v=3.0.1') format('woff'),
		url('http://cdnjs.cloudflare.com/ajax/libs/font-awesome/3.0.2/font/fontawesome-webfont.ttf?v=3.0.1') format('truetype');
	font-weight: normal;
	font-style: normal;
}

@errorcolor: #d23;
@accentcolor: #59d;
@formgutterwidth: 10px;

#restoreFontsize() {
	font-size: 15px;
	line-height: 1.333;
	word-spacing: 0;
}
#removeWhitespace() {
	font-size: .1%; // 0 doesn't always work, e.g. Safari 5/win
	line-height: 0;
	word-spacing: -.3em; // needed by browser with min font-size > 0, e.g. Opera
}
#boxsizing(@model: border-box) {
	-moz-box-sizing: @model;
	box-sizing: @model;
}
#transition(@params: all .2s) {
	-moz-transition: @params;
	-webkit-transition: @params;
	transition: @params;
}
#visuallyHidden() {
	position: absolute;
	z-index: -1;
	opacity: 0;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	clip: rect(0 0 0 0);
	overflow: hidden;
}

#starOn() {
	&:before {
		font-family: "FontAwesome";
		content: "\f005";
		// content: "\2605";
	}
}
#starOff() {
	&:before {
		font-family: "FontAwesome";
		content: "\f006";
		// content: "\2606";
	}
}

body {
	max-width: 1280px;
	margin: 0 auto;
	padding: 20px;
	background: #f2f2f2;
}
a {
	#transition;
	color: darken(@accentcolor, 8%);
	&:hover {
		color: lighten(@accentcolor, 4%);
	}
}
h1, h2, h3 {
	font-family: Georgia, serif;
}
h1 {
	margin-top: 0;
	text-align: center;
	text-transform: uppercase;
	font-size: 3em;
	letter-spacing: -2px;
	&:after {
		content: "❦";
		display: block;
		margin: .3em 0 1.3em;
		text-align: center;
		font-weight: normal;
	}
	span {
		display: block;
		font-size: 40%;
		text-transform: none;
		font-weight: normal;
		letter-spacing: 0;
	}
}
hr {
	margin: 1em 0;
	border: none;
	border-top: 1px solid #d9d9d9;
}

body,
input,
button,
select,
textarea {
	#boxsizing;
	#restoreFontsize;
	font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
}
button::-moz-focus-inner,
input::-moz-focus-inner {
    border: 0;
    padding: 0;
}
.placeholder {
	color: #999;
	font-style: italic;
}
:-moz-placeholder { .placeholder; }
:-ms-input-placeholder { .placeholder; }
::-webkit-input-placeholder { .placeholder; }

input[type="text"],
input[type="password"],
input[type="number"],
input[type="tel"],
input[type="email"],
input[type="url"],
input[type="date"],
input[type="time"],
input[type="month"],
input[type="week"],
input[type="datetime"],
input[type="datetime-local"],
select,
textarea {
	display: inline-block;
	margin: 4px 0;
	border: 1px solid #d9d9d9;
	padding: 6px;
	line-height: normal; // allows same height across browsers
	outline: none;
	box-shadow: inset 0 1px 1px rgba(0,0,0,.07);
	background: #fafafa;
	&:hover {
		border-color: #c0c0c0;
	}
	&:focus {
		border-color: @accentcolor;
	}
	&.error {
		border: 1px solid @errorcolor;
		color: @errorcolor;
	}
}
select {
	padding: 5px;
}
textarea {
	overflow-y: auto; // IE fix for consistency
}
fieldset {
	margin: 20px -20px;
	border: none;
	padding: 15px 20px;
	box-shadow: 0 2px 20px rgba(0,0,0,.1);
	background: #fff;
	.legend { // use with headlines; legend element is a bitch to style
		margin-top: 0;
	}
}

// grid
.formrow {
	.label {
		font-size: 12px;
		font-weight: bold;
		&.req:after {
			content: "*";
			color: @errorcolor;
		}
	}
	> .label {
		display: none; // hide shared labels
	}
	.formitem {
		display: inline-block;
		vertical-align: baseline;
		width: 100%;
		padding: 0 0 15px;

		// following rules will be needed in side-by-side layouts, won't hurt here
		// float any child to avoid breaking baseline-alignment of .labels...
		> * {
			float: left;
		}
		// ... except .label, of course
		> .label {
			float: none;
			display: block;
		}

		input[type="text"],
		input[type="password"],
		input[type="number"],
		input[type="tel"],
		input[type="email"],
		input[type="url"],
		input[type="date"],
		input[type="time"],
		input[type="month"],
		input[type="week"],
		input[type="datetime"],
		input[type="datetime-local"],
		select,
		textarea {
			width: 100%;
		}
		label.error {
			clear: left;
			font-size: 11px;
			font-weight: bold;
			color: @errorcolor;
		}
		.ticks {
			padding: 5px 0 0;
			label {
				#transition;
				display: inline-block;
				color: #999;
				&:hover { color: #666; }
				input.checked ~ span { color: #000; } // class "checked" for IE8
				input:checked ~ span { color: #000; } // separate to not confuse IE8

				// version 1
				> span {
					display: block;
					margin: 0 15px 5px 20px;
					cursor: default;
				}
				input[type="checkbox"],
				input[type="radio"] {
					float: left;
					margin: 1px -9px 0 0; // ensure label text doesn't start below input
					&.error ~ span {
						color: @errorcolor;
					}
				}

				// version 2
				// position: relative;
				// padding: 0 15px 5px 20px;
				// input[type="checkbox"],
				// input[type="radio"] {
				// 	position: absolute;
				// 	left: 0;
				// 	margin: 1px;
				// 	&.error ~ span {
				// 		color: @errorcolor;
				// 	}
				// }
			}
		}
		.rating {
			padding: 5px 0 0;
			label {
				#starOff;
				float: right; // direction:rtl and non-static positioning of input breaks in IE8
				width: 42px;
				height: 42px;
				font-size: 42px;
				line-height: 1;
				cursor: pointer;
				span {
					display: none;
				}
			}
			input {
				#visuallyHidden; // display:none would prevent submitting the value
			}
			label:hover,
			label:hover ~ label,
			input.checked ~ label { // class "checked" for IE8
				#starOn;
			}
			input:checked ~ label { // separate to not confuse IE8
				#starOn;
			}
			&:hover {
				input {
					~ label { #starOff; }
				}
				label:hover,
				label:hover ~ label { #starOn; }
			}
		}
	}
}

// respond! IE8 friendly - we just set body classes via JS (no respond.js)
.gt480 {
	body { padding: 40px; }
	fieldset {
		margin: 40px 0;
		padding: 30px 40px;
	}

	.formrow {
		#removeWhitespace;
		margin-right: -@formgutterwidth;
		.formitem {
			#boxsizing;
			#restoreFontsize;
			padding-right: @formgutterwidth;

			&:last-child {
				margin-right: -99px; // needed for older webkits (e.g. Safari 5, Android 2 stock browser)
			}

			// fake element which aligns with other .labels if current formitem has no .label:
			&:before {
				content: "\00a0";
				display: block;
				font-size: 12px;
        font-weight: bold; // same parameters as .label
				line-height: 15px;
				height: 15px;
				margin-top: -15px; // font-size * line-height
			}

			.rating label {
				width: 24px;
				height: 24px;
				font-size: 24px;
			}
		}
		.col1of1 { width: 100%; }
		.col1of2 { width: 50%; }
		.col1of3 { width: 33.33%; }
		.col2of3 { width: 66.66%; }
		.col1of4 { width: 25%; }
		.col3of4 { width: 75%; }
		.col1of5 { width: 20%; }
		.col2of5 { width: 40%; }
		.col3of5 { width: 60%; }
		.col4of5 { width: 80%; }
	}
}
.gt800 {
	body { padding: 80px; }

	.wideform .formrow {
		@labelwidth: 25%;
		@indent: @labelwidth / (100% - @labelwidth) * 100%;
		// #boxsizing;
		// width: 100%;
		padding-left: @labelwidth;
		> .label {
			#boxsizing;
			#restoreFontsize;
			font-size: 12px;
			display: inline-block;
			vertical-align: top;
			margin-left: -@indent;
			padding: 13px @formgutterwidth 20px (@formgutterwidth * @indent / 100%);
			width: @indent;
		}
		.formitem {
			vertical-align: top;
			&:before {
				content: none;
			}
			> .label {
				display: none;
			}
			.ticks,
			.rating {
				padding-top: 10px;
			}
		}
	}
}
@media screen and (min-width:481px) {
	.gt480;
}
@media screen and (min-width:801px) {
	.gt800;
}

// buttons
.button {
	#transition;
	display: inline-block;
	margin: 4px 0;
	border: 1px solid transparent;
	border: 1px solid rgba(0,0,0,.15);
	padding: 7px 16px; // top/bottom should be equal
	text-decoration: none;
	background: #e0e0e0;
	color: #333;
	border-radius: 2px;
	font-size: 12px;
	line-height: normal; // for same height as inputs
	font-weight: bold;
	cursor: pointer;
	outline: none;
	&:hover {
		background: #e5e5e5;
		border-color: rgba(0,0,0,.25);
		color: #000;
	}
	&:focus {
		box-shadow: inset 0 0 0 1px #fff;
	}
	&:active {
		#transition(none);
		background: #e0e0e0;
		box-shadow: inset 0 1px 3px rgba(0,0,0,.2);
	}
	&.disabled {
		background: #f2f2f2;
		border-color: rgba(0,0,0,.1);
		color: #999;
		box-shadow: none;
		cursor: not-allowed;
	}

	&.primary {
		background: @accentcolor;
		color: #fff;
		&:hover {
			background: lighten(@accentcolor, 4%);
			color: #fff;
		}
		&:active {
			background: @accentcolor;
		}
	}
	.buttons &,
	.formitem & {
		margin-right: @formgutterwidth;
	}
}
.buttons {
	text-align: right;
	margin-right: -@formgutterwidth;
	.forth {
		float: right;
	}
	.back {
		text-align: left;
	}
}

            
          
!
? ?
? ?
Must be a valid URL.
+ add another resource
via CSS Lint

JS

            
              // http://lea.verou.me/2009/02/check-if-a-css-property-is-supported/
// http://jsfiddle.net/leaverou/Pmn8m/
// IE fixed and modified from selector to rule to allow for @media query check
function supportsCssRule(rule) {
	var el = document.createElement("div");
	el.innerHTML = ["&shy;", "<style type='text/css'>", rule, "</style>"].join("");
	el = document.body.appendChild(el);
	var style = el.getElementsByTagName("style")[0],
		ret = !!((style.sheet && style.sheet.cssRules) || style.styleSheet.rules)[0];
	document.body.removeChild(el);
	el = null;
	return ret;
}


// :checked polyfill
if (!supportsCssRule(":checked{}")) {
	var checkedPolyfill = function() {
		var $input = $(this);
		if ($input.is(":checked")) {
			if ($input.is(":radio")) {
				$("[name='" + $input.attr("name") + "']").removeClass("checked");
			}
			$input.addClass("checked");
		} else if ($input.is(":checkbox")) {
			$input.removeClass("checked");
		}
	}
	$(document).on("click", ":radio, :checkbox", checkedPolyfill);
	$(":radio, :checkbox").each(checkedPolyfill);
}


// @media query simulation
if (!supportsCssRule("@media min-width:1px{a{}}")) {
	var oldBodyClass = document.body.className;
	var checkWindowWidth = function() {
		if (document.body.clientWidth > 800) {
			document.body.className = oldBodyClass + " gt480 gt800";
		} else if (document.body.clientWidth > 480) {
			document.body.className = oldBodyClass + " gt480";
		} else {
			document.body.className = oldBodyClass;
		}
	};
	checkWindowWidth();
	$(window).resize(checkWindowWidth);
}


// Placeholder polyfill
if (!("placeholder" in document.createElement("input"))) {
	$("input[placeholder], textarea[placeholder]").each(function() {
		var $input = $(this);
		$input.data("placeholder", $input.attr("placeholder"));
		$input.removeAttr("placeholder");

		var $clone = $input.clone();
		if ($clone.attr("type") == "password") {
			$clone = $("<input type='text'/>");
			$clone.attr("class", $input.attr("class"));
			$clone.attr("size", $input.attr("size"));
		}
		$clone.data("placeholder", $input.data("placeholder"));
		$clone.attr("readonly", "readonly");
		$clone.val($input.data("placeholder"));
		$clone.removeAttr("name");
		$input.removeAttr("id");
		$clone.addClass("ignore placeholder");
		if (!!$clone.attr("type") && $clone.attr("type").toLowerCase() == "password") {
			$clone.attr("type", "text");
		}
		$clone.css("display", $input.css("display"));
		$input.data("placeholder-input", $clone);
		$clone.data("orig-input", $input);
		$clone.hide();
		$input.before($clone);

		if (this.value == "") {
			$input.hide();
			$clone.show();
		} else {
			$clone.hide();
			$input.show();
		}

		$clone.on("focus", function() {
			var $placeholder = $(this);
			var $input = $placeholder.data("orig-input");
			$clone.hide();
			$input.show().focus();
		});
		$input.on("blur", function() {
			if (this.value == "") {
				var $placeholder = $input.data("placeholder-input");
				$input.hide();
				$placeholder.show();
			}
		});
	});
}


// create shared labels if not already given
$(".formrow").each(function() {
	var $formrow = $(this);
	if (!$formrow.children(".label").length) {
		var required = false;
		var labels = $.map($formrow.find(".label"), function(el) {
			if (el.className.indexOf("req") > -1)
				required = true;
			return el.innerHTML;
		}).join(", ");
		$formrow.prepend(
			$("<label class='label" + (required ? ' req' : '') + "'/>")
			.attr("for", $formrow.find(".label:first").attr("for"))
			.html(labels)
		);
	}
});


// jQuery Validate
$.validator.addMethod("pattern", function(value, element, param) {
	if (this.optional(element)) {
		return true;
	}
	if (typeof param === 'string') {
		param = new RegExp('^(?:' + param + ')$');
	}
	return param.test(value);
}, "Invalid format.");

$("form").validate({
	errorPlacement: function($err, $el) {
		$err.appendTo($el.closest(".formitem"));
	},
	rules: {
		passwordagain: {
			equalTo: "#password"
		}
	},
	messages: {
		zip: {
			pattern: "Please enter a valid zip code (5 digits)."
		}
	}
});




// Toggle label position - for demonstration
$(".js_toggleLabelPosition").click(function() {
	$("fieldset").toggleClass("wideform");
});

            
          
!
Must be a valid URL.
+ add another resource
via JS Hint
Loading ..................