facebook google plus twitter
Webucator's Free Advanced CSS Tutorial

Lesson: Laying Out and Styling Forms with CSS

Welcome to our free Advanced CSS tutorial. This tutorial is based on Webucator's Advanced CSS Training course.

HTML Forms are often laid out with two-column tables with the label in the left column and the form field in the right. One could argue that there is nothing semantically wrong with this as the labels are really like headers for the values in the form controls. However, that argument falls apart when table cells are joined (with colspan) to fit wider form controls such as textareas.

Even if you were to carefully layout the form so that the label were in the left column and the form field in the right, the table is not needed. The label tag serves the purpose of providing a "heading" for the form field.

In this lesson, we'll learn how to layout forms without tables using CSS.

Lesson Goals

  • Use CSS to layout forms.
  • Use related HTML5 form-field tags and attributes.

Laying out the Questions

Most forms can be thought of as a series of questions:

  1. What is your first name?
  2. What is your last name?
  3. What company do you work for?

But instead of being laid out as questions, they are presented as answer spaces (form controls) preceded by labels:

  1. First Name: __________________________
  2. Last Name: __________________________
  3. Company: __________________________

So, in creating an HTML page, it makes sense to use an ordered list. In fact, let's start with that: Ordered List

The code for this page is shown below:

Code Sample:

CssForms/Demos/JobApplication1.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Job Application</title>
</head>
<body>
<h1>Job Application</h1>
<h2>Job Information</h2>
<ol>
	<li>Job of Interest (Sales Manager, Account Executive, Receptionist, Marketing Director)</li>
	<li>Referral Source (Advertisement, Employee, Employement Agency, Website)</li>
	<li>Availability (Full-Time, Part-Time, Temporary, Seasonal)</li>
	<li>Location (New York, California, Texas, Pennsylvania, Kansas)</li>
</ol>
<h2>Personal Information</h2>
<ol>
	<li>First Name</li>
	<li>Last Name</li>
	<li>Street Address</li>
	<li>City</li>
	<li>State</li>
	<li>Postal code</li>
	<li>Telephone</li>
	<li>Email address</li>
	<li>Citizenship</li>
	<li>Have you ever been convicted of a felony?</li>
	<li>Are you willing to relocate?</li>
</ol>
<h2>Employment History</h2>
<p>Provide your employment history starting with the company for which you have most recently worked.</p>
<ol>
	<li>Company 1
		<ol>
			<li>Company Name</li>
			<li>Job Title</li>
			<li>Start Date</li>
			<li>End Date</li>
			<li>Responsibilities</li>
			<li>Reason for leaving</li>
		</ol>
	</li>
	<li>Company 2
		<ol>
			<li>Company Name</li>
			<li>Job Title</li>
			<li>Start Date</li>
			<li>End Date</li>
			<li>Responsibilities</li>
			<li>Reason for leaving</li>
		</ol>
	</li>
	<li>Company 3
		<ol>
			<li>Company Name</li>
			<li>Job Title</li>
			<li>Start Date</li>
			<li>End Date</li>
			<li>Responsibilities</li>
			<li>Reason for leaving</li>
		</ol>
	</li>
</ol>
</body>
</html>

Code Explanation

As you can see, there is no CSS in this file. It's a simple HTML file split into separate sections of pseudo-questions, which are presented in ordered lists.

The pseudo-questions will become our form labels.

Creating the Form

Now we'll begin creating the form. We won't add the form controls just yet. First, we want to capture the structure within a form:

Code Sample:

CssForms/Demos/JobApplication2.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Job Application</title>
<style>
	/* added to call out fieldsets */
	fieldset {
		border-color: #000;
	}
	fieldset fieldset {
		border-style: dashed;
	}
</style>
</head>
<body>
<h1>Job Application</h1>
<form method="post" action="apply.php">
	<fieldset>
		<legend>Job Information</legend>
		<ol>
			<li>Job of Interest (Sales Manager, Account Executive, Receptionist, Marketing Director)</li>
			<li>Referral Source (Advertisement, Employee, Employement Agency, Website)</li>
			<li>Availability (Full-Time, Part-Time, Temporary, Seasonal)</li>
			<li>Location (New York, California, Texas, Pennsylvania, Kansas)</li>
		</ol>
	</fieldset>
	<fieldset>
		<legend>Personal Information</legend>
		<ol>
			<li>First Name</li>
			<li>Last Name</li>
			<li>Street Address</li>
			<li>City</li>
			<li>State</li>
			<li>Postal code</li>
			<li>Telephone</li>
			<li>Email address</li>
			<li>Citizenship</li>
			<li>Have you ever been convicted of a felony?</li>
			<li>Are you willing to relocate?</li>
		</ol>
	</fieldset>
	<fieldset>
		<legend>Employment History</legend>
		<p>Provide your employment history starting with the company for which you have most recently worked.</p>
		<fieldset>
			<legend>Company 1</legend>
			<ol>
				<li>Company</li>
				<li>Title</li>
				<li>Start Date</li>
				<li>End Date</li>
				<li>Responsibilities</li>
				<li>Reason for leaving</li>
			</ol>
		</fieldset>
		<fieldset>
			<legend>Company 2</legend>
			<ol>
				<li>Company</li>
				<li>Title</li>
				<li>Start Date</li>
				<li>End Date</li>
				<li>Responsibilities</li>
				<li>Reason for leaving</li>
			</ol>
		</fieldset>
		<fieldset>
			<legend>Company 3</legend>
			<ol>
				<li>Company</li>
				<li>Title</li>
				<li>Start Date</li>
				<li>End Date</li>
				<li>Responsibilities</li>
				<li>Reason for leaving</li>
			</ol>
		</fieldset>
	</fieldset>
	<fieldset>
		<input type="reset" id="Reset" name="Reset" value="Start Over">
		<input type="submit" id="Submit" name="Submit" value="Submit">
	</fieldset>
</form>
</body>
</html>

Code Explanation

Things to notice:

  • In JobApplication1.html, we had used a nested ordered list to capture the parent-child relationship between "Employment History" and the individual companies for which the applicant has worked. Here in JobApplication2.html, we've replaced that structure with nested fieldsets.
  • We have also replaced all the h2 tags with legend tags.
  • We have added buttons nested in a fieldset.

The result is shown below. Note that we have styled the fieldset borders some to call them out. We'll remove those styles later. Fieldset Borders Styled

The fieldset tag is used to group like form fields. The legend tag is not required in a fieldset, but it is usually a good idea to include it. It provides a title or heading for the grouped elements.

HTML5 Form Fields

HTML5, the newest version of HTML, introduced a range of new types for input tags, giving us greater control over the type of data we expect from our users in forms. Rather than presenting any single-line text field as an input of type text, we can specify more exactly that we are looking here for an email address, say, or a telephone number. These new fields are especially useful: an iPhone keypad will present the user with a phone-pad set of keys when the user taps into a field of type tel. Keep in mind that support for these newer HTML5 form tags is not 100% among all browsers; as always, if you expect significant traffic to your pages from folks who use older version of browsers, it might be best to avoid using these tags.

Note that the date type will work well - presenting a date picker - on most mobile devices, but works on desktop browsers (as of this writing) only in Chrome and Opera.

We'll use the telephone (tel), email, and date input types in our example below:

Code Sample:

CssForms/Demos/JobApplication3.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Job Application</title>
</head>
<body>
<h1>Job Application</h1>
<form method="post" action="apply.php">
	<fieldset id="jobInfo">
		<legend>Job Information</legend>
		<ol>
			<li>
				<label for="JobOfInterest">Job of Interest:</label>
				<select name="JobOfInterest" id="JobOfInterest">
					<option>Account Executive</option>
					<option>Marketing Director</option>
					<option>Receptionist</option>
					<option>Sales Manager</option>
				</select>
			</li>
			<li>
				<label for="ReferralSource">Referral Source</label>
				<select name="ReferralSource" id="ReferralSource">
					<option>Advertisement</option>
					<option>Employee</option>
					<option>Employement Agency</option>
					<option>Website</option>
				</select>
			</li>
			<li>
				<label for="Availability">Availability</label>
				<select name="Availability" id="Availability">
					<option>Full-Time</option>
					<option>Part-Time</option>
					<option>Seasonal</option>
					<option>Temporary</option>
				</select>
			</li>
			<li>
				<label for="Location">Location</label>
				<select name="Location" id="Location">
					<option>California</option>
					<option>Kansas</option>
					<option>New York</option>
					<option>Texas</option>
					<option>Pennsylvania</option>
				</select>
			</li>
		</ol>
	</fieldset>
	<fieldset id="personalInfo">
		<legend>Personal Information</legend>
		<ol>
			<li>
				<label for="FirstName">First Name:</label>
				<input type="text" size="20" name="FirstName" id="FirstName" title="First Name">
			</li>
			<li>
				<label for="LastName">Last Name:</label>
				<input type="text" size="20" name="LastName" id="LastName" title="Last Name">
			</li>
			<li>
				<label for="Address">Street Address:</label>
				<input type="text" size="20" name="Address" id="Address" title="Address">
			</li>
			<li>
				<label for="City">City:</label>
				<input type="text" size="20" name="City" id="City" title="City">
			</li>
			<li>
				<label for="State">State:</label>
				<input type="text" size="20" name="State" id="State" title="State">
			</li>
			<li>
				<label for="PostalCode">Postal Code:</label>
				<input type="text" size="20" name="PostalCode" id="PostalCode" title="Postal Code">
			</li>
			<li>
				<label for="Telephone">Telephone:</label>
				<input type="tel" size="20" name="Telephone" id="Telephone" title="Telephone">
			</li>
			<li>
				<label for="Email">Email Address:</label>
				<input type="email" size="20" name="Email" id="Email" title="Email Address">
			</li>
			<li>
				<label for="Citizenship">Citizenship:</label>
				<input type="text" size="20" name="Citizenship" id="Citizenship" title="Citizenship">
			</li>
			<li>
				<span class="label">Have you ever been convicted of a felony?:</span>
				<label><input type="radio" name="Felony" id="FelonyYes" title="Felony Yes"> Yes</label>
				<label><input type="radio" name="Felony" id="FelonyNo" title="Felony No"> No</label>
			</li>
			<li>
				<span class="label">Are you willing to relocate?:</span>
				<label><input type="radio" name="Relocate" id="RelocateYes" title="Relocate Yes"> Yes</label>
				<label><input type="radio" name="Relocate" id="RelocateNo" title="Relocate No"> No</label>
			</li>
		</ol>
	</fieldset>
	<fieldset id="employmentHistory">
		<legend>Employment History</legend>
		<p>Provide your employment history starting with the company for which you have most recently worked.</p>
		<fieldset>
			<legend>Company 1</legend>
			<ol>
				<li>
					<label for="CompanyName1">Company Name:</label>
					<input type="text" size="20" name="CompanyName1" id="CompanyName1" title="Company Name">
				</li>
				<li>
					<label for="JobTitle1">Job Title:</label>
					<input type="text" size="20" name="JobTitle1" id="JobTitle1" title="Job Title">
				</li>
				<li>
					<label for="StartDate1">Start Date:</label>
					<input type="date" size="20" name="StartDate1" id="StartDate1" title="Start Date">
				</li>
				<li>
					<label for="EndDate1">End Date:</label>
					<input type="date" size="20" name="EndDate1" id="EndDate1" title="End Date">
				</li>
				<li>
					<label for="Responsibilities1">Responsibilities:</label>
					<textarea name="Responsibilities1" id="Responsibilities1" title="Responsibilities" cols="50" rows="3"></textarea>
				</li>
				<li>
					<label for="ReasonForLeaving1">Reason for Leaving:</label>
					<textarea name="ReasonForLeaving1" id="ReasonForLeaving1" title="Reason for Leaving" cols="50" rows="3"></textarea>
				</li>
			</ol>
		</fieldset>
---- C O D E   O M I T T E D ----

	</fieldset>
	<fieldset id="buttons">
		<input type="reset" id="Reset" name="Reset" value="Start Over">
		<input type="submit" id="Submit" name="Submit" value="Submit">
	</fieldset>
</form>
</body>
</html>

Code Explanation

Adding the Form Fields

The page still uses all the default HTML styles. The result is shown below: Page Still Using HTML Styles

Our form is now well structured so that a person viewing it in a browser or using an accessibility device such as a screen reader would be able to follow it easily. A few things to note:

  • We have placed most of the "questions" in label tags and used the for attribute to tie them to their form fields.
  • We have wrapped the radio buttons with their labels in label tags and put the associated questions in span tags, which we have given a "label" class so that we can style them later.
  • We have used the title attribute on all the form fields and assigned it a descriptive value. This is for accessibility purposes. Though most accessibility devices will use the label tag to provide information about the form control, some rely on the control's title attribute.
  • We used types tel (for phone), email, and date where appropriate to the type of information being requested. Sadly, our date type present a date picker only on mobile devices and Chrome: Chrome date picker
  • We have added id attributes to the main fieldsets as hooks for our style sheet.

It's almost time to get stylish. We won't need any new CSS properties to style our form. We'll just see how we can use styles we're already familiar with. However, before we do that, we need to go on a little tangent.

Reset Revisited

  • Introduced in Page Layout lesson
  • cr

In the Page Layout lesson, we introduced the following simple CSS reset:

* {
	margin:0;
	padding:0;
	border:0;
}

As we noted there, this effectively does away with all margin, padding and borders for every element. This includes form controls. However, resetting form control styles has some undesirable effects. Eric Meyer covers this in detail in his article at http://meyerweb.com/eric/thoughts/2007/05/15/formal-weirdness. The big takeaway is that different browsers have different default displays for form controls and that it is not possible to reconstruct those displays using CSS, so it's generally better to leave form controls alone.

Meyer provides a more detailed reset at http://meyerweb.com/eric/tools/css/reset/index.html that avoids resetting form controls. You'll find a copy of this file (reset-meyer.css in your CssForms directory. And we will use it in our code here.

Styling the Form

We've just said that we don't want to use CSS to style any of the form controls. But we do want to use CSS to layout the form and we can apply some formatting styles to the form, fieldset and legend elements.

First let's see what happens when we apply Eric Meyer's reset to CssForms/Demos/JobApplication4.html: Rest Applied

Not pretty, but it gives us a fresh start.

Before we style our form, let's look at another HTML5 attribute which, while not CSS, comes in handy when presenting forms: the placeholder attribute. It's often useful for users to see an example of the type of content we're expecting for a given field. A simple search text box might, for instance, display the word "search" in the box, giving the user a clear indication - without any label instructions or even a button next to it - the meaning and purpose of that particular text field. The HTML placeholder attribute:

<input type="text" name="searchfield" id="searchfield" placeholder="search">

will display the placeholder text until the user types in the field, after which the placeholder will disappear. We'll use the placeholder attribute in our "Job Title" field.

Now let's see what we need to do to the style sheet to make CssForms/Demos/JobApplication5.html look like this: Style Sheet

Let's start by looking at the complete style sheet and then we'll dissect it:

Code Sample:

CssForms/Demos/style.css
body {
	background-color:#ccc;	
}

h1 {
	width: 555px;
	margin: 5px auto;
	padding-bottom: 10px;
	border-bottom: 1px solid #930;
	font-size: xx-large;
	color: #930;
}

/*Begin Form Styles*/
form {
	width: 555px;
	margin: auto;
	padding-bottom: 20px;
	color: #930;
}

fieldset {
	margin-bottom: 10px;
	border-bottom: 1px solid #930;
	background-color: #eec;
}

legend {
	padding-left: 10px;
	font-size: 1.2em;
	font-weight: bold;
	letter-spacing: .5em;
	font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
	font-variant: small-caps;
	color: #460;
}

fieldset fieldset {
	margin-top: 10px;	
	border-bottom: none;
}

fieldset fieldset legend {
	font-size: 1em;
	font-weight: bold;
	letter-spacing: .4em;
	font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
	color: #333;
}

form ol {
	padding: 20px;
}

fieldset fieldset ol {
	margin-top: -10px;
}

form p {
	margin: 10px;
	font-size: .8em;
}

form li {
	list-style-type: none;
	border-bottom: 1px dotted #000;	
	padding-bottom: 2px;
	margin-bottom: 2px;
}

label {
	width: 200px;
	float: left;
	font-weight: bold;
}

span.label {
	font-weight: bold;
}

li.radioContainer label {
	display: block;
	float: none;
	font-weight: normal;
}

select, input[type="text"] {
	width :200px;	
}

textarea {
	width: 400px;
	height: 50px;
}

#buttons {
	text-align: center;	
}

#buttons input {
	height: 50px;
	width: 150px;
	font-size: 1.5em;
	color: #930;
	font-variant: small-caps;
	margin: 10px;
}
/*End Form Styles*/

Code Explanation

Most of the CSS should be pretty easy to follow. Here are some things to notice:

  1. The rule below takes away the bottom border from fieldsets that are nested within other fieldsets:
    fieldset fieldset {
    	margin-top: 10px;	
    	border-bottom: none;
    }
  2. The selector fieldset fieldset legend only applies to legends inside of fieldsets that are nested within other fieldsets. This is to make the "headings" of form subsections appear differently from the headings of the main sections.
  3. The rule below removes the numbers from the list items, adds a dotted line beneath each "question", and creates some vertical space between the "questions."
    form li {
    	list-style-type: none;
    	border-bottom: 1px dotted #000;	
    	padding-bottom: 2px;
    	margin-bottom: 2px;
    }
  4. The float: left; declaration changes the element from inline to block, which will bring its associated form control up to the right of the label:
    label {
    	width: 200px;
    	float: left;
    	font-weight: bold;
    }
  5. This rule turns off the float property for labels that appear in list items with the "radioContainer" class. Since the label is not floated anymore it will revert back to displaying inline. To keep it displayed on a separate line we add in the display:block; setting:
    li.radioContainer label {
    	display: block;
    	float: none;
    	font-weight: normal;
    }
    Remember, these are the label elements that surround the radio button and its presentation value, like this:
    <li class="radioContainer">
    	<span class="label">Have you ever been convicted of a felony?:</span>
    	<label><input type="radio" name="Felony" id="FelonyNo" title="Felony Yes" /> Yes</label>
    	<label><input type="radio" name="Felony" id="FelonyYes" title="Felony No" /> No</label>
    </li>
  6. This rule sets a width for the select and text input elements:
    select, input[type="text"] {
    	width: 200px;	
    }
  7. This rule sets a height and width for the textareas, overriding the cols and rows values:
    textarea {
    	width: 400px;
    	height: 50px;
    }
  8. And these last two rules style the buttons:
    #buttons {
    	text-align:center;	
    }
    
    #buttons input {
    	height: 50px;
    	width: 150px;
    	font-size: 1.5em;
    	color: #930;
    	font-variant: small-caps;
    	margin: 10px;
    }
    Note that we recommended earlier that you should leave form controls alone. Changing the height and width of form controls doesn't change any of their other default behaviors or styles, so this is not necessarily bad, but you should certainly test it carefully in all your target browsers and operating systems.

Although there are other ways to layout the HTML for forms, we like the use of an ordered list as it makes sense semantically and doesn't require extraneous tags used for formatting purposes only.

Expanding the Form

Duration: 10 to 25 minutes.

In this exercise, you will add an "Education" section to the form.

  1. Open CssForms/Exercises/JobApplication.html in your editor.
  2. Expand the form to cover the following:
    1. Education
      1. Degree 1
        1. Institution
        2. Type of Degree
        3. Year Completed
        4. Comments
      2. Degree 2
        1. Institution
        2. Type of Degree
        3. Year Completed
        4. Comments

Challenge

Try to layout the form in two columns like this: Two-Column Layout

Note that there are several ways to do this; our solution uses relative positioning and the screenshot is from Firefox. It would look almost the same in other modern browsers.

Solution:

CssForms/Solutions/JobApplication.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="../reset-meyer.css">
<link rel="stylesheet" href="style.css">
<title>Job Application</title>
</head>
<body>
<h1>Job Application</h1>
<form method="post" action="apply.php">
---- C O D E   O M I T T E D ----
<fieldset id="education">
		<legend>Education</legend>
		<fieldset>
			<legend>Degree 1</legend>
			<ol>
				<li>
					<label for="Institution1">Institution:</label>
					<input type="text" size="20" name="Institution1" id="Institution1" title="Institution">
				</li>
				<li>
					<label for="TypeOfDegree1">Type of Degree:</label>
					<select name="TypeOfDegree1" id="TypeOfDegree1" title="Type of Degree">
						<option>Please select...</option>
						<option>High School</option>
						<option>Bachelors</option>
						<option>Masters</option>
						<option>PhD</option>
					</select>
				</li>
				<li>
					<label for="YearCompleted1">Year Completed:</label>
					<input type="text" size="20" name="YearCompleted1" id="YearCompleted1" title="Year Completed">
				</li>
				<li>
					<label for="Comments1">Comments:</label>
					<textarea name="Comments1" id="Comments1" title="Comments" cols="50" rows="3"></textarea>
				</li>
			</ol>
		</fieldset>
		<fieldset>
			<legend>Degree 2</legend>
			<ol>
				<li>
					<label for="Institution2">Institution:</label>
					<input type="text" size="20" name="Institution2" id="Institution2" title="Institution">
				</li>
				<li>
					<label for="TypeOfDegree2">Type of Degree:</label>
					<select name="TypeOfDegree2" id="TypeOfDegree2" title="Type of Degree">
						<option>Please select...</option>
						<option>High School</option>
						<option>Bachelors</option>
						<option>Masters</option>
						<option>PhD</option>
					</select>
				</li>
				<li>
					<label for="YearCompleted2">Year Completed:</label>
					<input type="text" size="20" name="YearCompleted2" id="YearCompleted2" title="Year Completed">
				</li>
				<li>
					<label for="Comments2">Comments:</label>
					<textarea name="Comments2" id="Comments2" title="Comments" cols="50" rows="3"></textarea>
				</li>
			</ol>
		</fieldset>
	</fieldset>
	<fieldset id="buttons">
		<input type="reset" id="Reset" name="Reset" value="Start Over">
		<input type="submit" id="Submit" name="Submit" value="Submit">
	</fieldset>
</form>
</body>
</html>

Code Explanation

Challenge Solution:

CssForms/Solutions/style-challenge.css
body {
	background-color: #ccc;	
}

h1 {
	width: 1000px;
	margin: 5px auto;
	padding-bottom: 10px;
	border-bottom: 1px solid #930;
	font-size: xx-large;
	color: #930;
}

/*Begin Form Styles*/
form {
	width: 1000px;
	margin: auto;
	padding-bottom: 20px;
	color: #930;
}

fieldset {
	width: 480px;
	margin-bottom: 10px;
	border-bottom: 1px solid #930;
	background-color: #eec;
}
---- C O D E   O M I T T E D ----
#buttons input {
	height: 100px;
	width: 350px;
	font-size: 1.5em;
	background-color: #cc9;
	color: #930;
	border: 1px solid;
	font-variant: small-caps;
	margin: 10px;
	cursor: pointer;
}

#buttons input:hover {
	background-color: #dda;
}

#jobInfo {
	height: 164px;
}

#personalInfo {
	display: block;
	position: relative;
	left: 520px;
	top: -175px;
	height: 419px;
}

#employmentHistory {
	display: block;
	position: relative;
	top: -430px;
	height: 1021px;
}

#education {
	display: block;
	position: relative;
	top: -1205px;
	left: 520px;
	height: 458px;
}

#buttons {
	display: block;
	padding: 27px 0px;
	position: relative;
	top: -1205px;
	left: 520px;
	text-align: center;	
}
/*End Form Styles*/

Code Explanation

Open CssForms/Solutions/JobApplication-challenge.html in your browser to see the result.