Skip Navigation
The Illuminating Web
 
 

Getting It All, With CSS

In this three part series we will explore the potential of Cascading Style Sheets (CSS) to make life simpler. While it is true that CSS support is still not a guarantee among everyone in your web audience, the availability is high enough that most users that would benefit from it already have it, and those that do not have it may be better served by unstyled, but well structured content.

Part 1 : Format and Positioning with Forms

CSS is a large and very complex specification. This introduction uses form elements to illustrate the power of CSS. Styling content is a useful application, but under-representative of the possibilities. Using CSS for layout is a great way to show off what it can do, but is very involved. Using form elements as an example allows for a simple introduction to both the styling and positioning capabilities of CSS.

What You Will Need

  • A Text Editor; WYSIWYG HTML editors are fine, but all you really need is a text editor. Understanding CSS requires working with the tags.
  • A Browser; Mozilla Firefox, Opera 8, or Safari are recommended. Internet Explorer is always important to test in (since most people use it), but it is not very compliant with the specifications.
  • These Files

What You Can Learn

  • The basic gist of HTML
  • How to make an accessible HTML form
  • How to format and position an HTML (HTML 4.01 and XHTML 1.1) form with CSS
  • Basic CSS formatting and positioning

What You Won't Learn

  • HTML in depth
  • Form processing (Sever or Client Side)
  • XHTML 2 XForms
  • Advanced CSS

 

Building a Form

In this tutorial we will build an HTML form. Attaching this form to a server side script to process the data is beyond the scope of the discussion, so we will only be concerned with the appearance and usability of the form we create. There will be no client-side scripts like Javascript used either. While this limits the level of dynamic interactivity that can be achieved, what can and cannot be done with CSS will be more apparent.

Step 1 - Tag Introduction For Almost Complete Beginners
( the most thorough and succinct introduction to HTML you'll ever find, in this tutorial )

If you already know HTML Skip to Step 2 .

What is HTML? HTML stands for Hypertext Markup Language. Put simply, hypertext is a text document with "links" to other text documents to make finding related information easier. A markup language is a way to embed additional information into a text document. Historically this information was a shorthand notation used among publishers and editors to indicate formatting. In the case of HTML it indicates not just formatting, but linking information, references to graphics, and various semantic specializations for the text, such as section headers, lists, data tables, definitions, and quotes.

Let's begin with a plain and relatively empty HTML file. For users with little experience with HTML the following primer will help get you up to speed. An blank HTML document would look something like this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title>Untitled Document</title>
  </head>
  <body>

  </body>
</html>

What are these tags? HTML tags come in different flavors. All tags start with a "<", less than sign, and end with a ">" , greater than sign. In some circles these are called "left angle bracket" and "right angle bracket". What is important is that they enclose a tag and always appear in HTML documents in pairs. There are three types of tags you will commonly encounter:

  • <p> and <img src="somepicture.jpg"> - Tags that start and end with with no "/" are open tags. They indicate that the tag applies to the text that follows. Open tags begin with the tag's name and may be followed by a list of "x=y" statements. These statements are called "attributes" and are not part of the text of the tag. Text associated with an open tag appears after the ">".
  • </p> and </a> - Tags that start with both a "<" and a "/" are close tags. A close tag applies to the text that appears before it. Nothing should appear in a close tag except the same tag name that is in the corresponding open tag. Close tags are usually paired with open tags to mark a region of text. In older variants of HTML close tags are sometimes optional, but in the newer versions of the standard (XHTML) close tags are always required.
  • <br/> and <img/> - Tags that end with a "/" and a ">" are empty tags, meaning they do not wrap around or mark any text. Since the introduction of XHTML these tags have become more common. In older versions of HTML <br> and <br/> have the same meaning. The "br" tag is a line break indicator, and does not wrap text. Since it was always assumed to not wrap any text, the close tag was not needed. Modern XHTML requires all open tags to be closed. This prevents ambiguity. Then use of an empty tag for some applications prevents the need to write out something unnecessarily long, such as <br></br>. In XHTML the br tag may not contain anything, so <br/> is the only expected form.

Other types of tags you might see include:

  • <!-- insert comment here --> - Comment tags allow notes to be placed in an HTML document without appearing in output. These tags are used by humans or programs to mark a location, store information, or make notes.
  • <!declaration > - Declaration tags give specific information about a document and it's content to a web browser or other program. These tags are usually only encountered in HTML documents at the top as declarations of the version of HTML being used. In XHTML they have other uses.
  • <? processor instructions ?> Instruction tags are also used by browsers, servers, and other programs. These tags give specific directions to one or more programs, and can be seen in XML documents and PHP programs.

Tags wrap text to apply some semantic meaning. For example, the "p" or paragraph tag is used to indicate a region of text that constitutes one paragraph. The open and close tag indicate where the paragraph begins and ends:

<p> A paragraph goes here </p>

Tags can appear inside one another, this is called nesting. There are rules that dictate what tags may appear inside others. Bold (b), italics (i), and link (a) tags can appear inside the paragraph tag, but paragraph and header (h1, h2, etc.) tags may not.

<p> A <b> paragraph </b> goes here. This is a <i>valid</i> example</p> 
<p> 
  <h1> Not a valid example </h1> 
  A paragraph goes here. <p> Another one should not be found inside </p> 
</p>

Tags can be nested, but they cannot be intertwined as in the example below:

<p> A paragraph goes here. <b> Important </p> 
<p> information might be in bold </b>. But the bold tag is not properly nested. </p>   

Going back to the example, The black html tag is obvious. It wraps the contents of the page, indicating that the information inside is HTML. The tag colored in red above is the document type declaration. While many pages on the web may not have this tag, it is becoming increasingly more common. It describes, to the web browser, what version of HTML is used in the page. HTML has evolved over the past decade and is entering it's 6th major revision, XHTML 2.0. For the purpose of CSS it does not matter what version of HTML you are working with. CSS can even be used with documents made with other markup languages.

Inside the black html tag are the two major portions of all HTML documents. The head and the body. The head tag shouldn't be confused with a "header", which one would expect to appear at the top of the document. The head of an HTML document contains information important to the web browser, but that is not shown to the user. All of the text that the user sees is present in the body of the HTML document.

  <head>
     <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
     <title>Untitled Document</title>
  </head> 
              

Inside the head tag there are two tags. The first is an open meta tag with no close. This is OK since this is an HTML 4.0 document, not XHTML. Meta tags are used by the browser and search engines for various bits of technical information. This meta tag informs the browser that this document is an HTML document, in case there was any confusion. It also indicates that the document uses a particular character set, which is important on the internet because computers supporting different foreign languages use different character sets. Another common application of meta tags is to indicate key words for search engines.

The title tag is also used by the browser and search engines. It indicates a title for the document, but since it is in the head it will not appear as part of the text of the document on most browsers. In most window based web browsers (Internet Explorer, Firefox, Opera) the title of the current document will appear at the top of the window, or just below the address bar. Titles are important and every document should have a meaningful title.

Step 2 - Change the Head

Change the title to, "An accessible form made attractive with CSS".

  <head>
     <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
     <title>An accessible form made attractive with CSS</title>
  </head>

Next add a style tag to the document. This will contain the CSS that formats and positions the form. It can go anywhere in the head, but after the title is a preferred location.

  <head>
     <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
     <title>An accessible form made attractive with CSS</title> 
     <style></style>
  </head> 

For absolute clarity, the "type" attribute of the style tag can be set to indicate that is it a CSS rather than some other, less standard, style specification. This may not be necessary, but is preferred.

  <head>
     <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
     <title>An accessible form made attractive with CSS</title> 
     <style type="text/css"></style>
  </head> 

After these changes to the head the document should look like this.

Step 3 - Add Content To the Body

Next the document needs some content in the body. Add an "h1" header with text matching title of the page, followed by a paragraph tag that says, "Please fill out all required fields, any additional information that is applicable, and press the send button."

  <body>
     <h1>An accessible form made attractive with CSS</h1>
     <p>Please fill out all required fields, 
any additional information that is applicable, 
and press the send button.
    </p>
  </body>

Step 4 - Add a Form Tag To The Body

After the content insert a form tag. The three important attributes of any form are:

  • an "action", the URL of the script that will process the data.
  • a "method", how the script will receive the information. There are two options for this. The "post" method hides the submitted information and makes the resulting page impossible to bookmark. The "get" method appends the submitted information to the URL of the script. It will appear in the address bar and the same results can be called up again later by bookmarking the page or sending the full URL to someone else in e-mail. Some scripts only allow one of the methods while others may allow both. The method that should be used depends on the function of the form. Information that should be sharable needs the "get" method, while information that is best kept private, or one time transactions should use the "post" method.
  • a "title" describing the function of the form is helpful in some cases, especially on pages with more than one form. This improves usability in some browsers and also improves accessibility.
  <body>
     <h1>An accessible form made attractive with CSS</h1>
     <p>Please fill out all required fields, 
any additional information that is applicable, 
and press the send button.
    </p>
    <form action="script.php" method="post" title="Personal Information"> </form>
  </body>

Step 5 - Make Some Form Elements

First add a text field for name, one for nickname, and a text area (multiple lines) for a short "bio".

<form action="script.php" method="post" title="Personal Information">
  <p>Your Name
<input type="text" name="name">
</p>
<p>Nickname
<input type="text" name="nick" value="no nickname">
</p>
<p> Short Bio
<textarea name="bio"></textarea>
</p> </form>

Inside the form tag, input tags create a place to fill out information. Input tags appear differently depending on their "type" attribute. Single line text fields are of the type "text". Multi-line text fields are treated differently than most other input tags. The textarea tag can wrap a default value to appear in the text box. Most other input tags use the "value" attribute. The "name" attribute is used to give each input an identifier that the scripts can use. Except with checkboxes and radio buttons, these names should usually be unique.

Next add a list of check boxes for "flavors of ice cream". Add an option with additional text field for "other".

<form action="script.php" method="post" title="Personal Information">
  ...
  <p>What flavors of ice cream do you like?</p>
<p>
<input type="checkbox" name="icecream[]" value="vanilla">
Vanilla
<input type="checkbox" name="icecream[]" value="chocolate">
Chocolate
<input type="checkbox" name="icecream[]" value="strawberry">
Strawberry<br>
<input type="checkbox" name="icecream[]" value="other">
Other
<input type="text" name="other icecream">
</p>
</form>

The checkbox input type allows a user to select zero or more (possibly all) related choices. In order for checkboxes to be grouped they must share the same name attribute. Browsers will only send one value per name in a form. To get around this limitation you can add a pair of square brackets to the end of the name. The browser will bundle the values together as an "array". Some scripting languages can accept an array of data from the browser, others cannot. If arrays are not an option then the form will have to give a unique name to each checkbox (such as icecream1, icecream2, etc.) and programmatically combine the data itself. A form written this way might look like:

 <input type="checkbox" name="icecream vanilla" value="y">
 Vanilla
 <input type="checkbox" name="icecream chocolate" value="y">
 Chocolate 

or:

 <input type="checkbox" name="icecream1" value="vanilla">
 Vanilla
 <input type="checkbox" name="icecream2" value="chocolate">
 Chocolate 

depending on the programmer's style. Checkboxes are not the only type of input that can be grouped into an array. All form inputs can be grouped this way, even if they are of different types. All that is required is that they have the same name and end with the square brackets. Form elements with the same name can cause problems when trying to manipulate forms with client-side Javascript. If this is the case, assigning a unique "id" attribute to each form element can get around the problem. Unlike the "name" attribute, the "id" of every form element must be unique.

Next add a list of radio buttons for "what pet would you get? ". Add an option with additional text field for "other".

<form action="script.php" method="post" title="Personal Information">
  ...
<p>If you could get a pet it would be a:</p>
<p>
<input name="pet" type="radio" value="no pet">
I do not want a pet <br>
<input name="pet" type="radio" value="kitten">
Kitten
<input name="pet" type="radio" value="cat">
Adult Cat
<input name="pet" type="radio" value="puppy">
Puppy
<input name="pet" type="radio" value="dog">
Adult Dog
<input name="pet" type="radio" value="bird">
Bird
<input name="pet" type="radio" value="fish">
Fish<br>
<input name="pet" type="radio" value="other">
Other
<input type="text" name="other pet">
</form>

The radio button input type allows a user to select only one of the related choices. In order for radio buttons to be grouped they must share the same name attribute. The browser will then only allow the user to select one, deselecting any others in the same group.

Next add a list of states with the question "what state were you born in? ".

<form action="script.php" method="post" title="Personal Information">
  ...
  <p> State of Birth
<select name="birth state">
<option value="NC">North Carolina</option>
<option value="GA">Georgia</option>
<option value="SC">South Carolina</option>
<option value="TN">Tennessee</option>
<option value="VA">Virginia</option>
<option value="O">Other</option>
</select>
</p>
</form>

The "select" tag creates a different type of list of options from the radio button input type. The select tag gets the "name" attribute for the whole list of options. Inside, the option tag gets the "value" attribute. The option tag also wrap a textual representation of the value. The option tag's value and the text that the option tag wraps can be the same, but often the value alttribute is a shorthand representation.. The value in the tag is what the web user will see and the value in the attribute is what the script will receive. By default, the select tag is shown to the user as a drop down list. It becomes a scroll box if the "size" attribute is set to a number. The "size" attribute indicates how many options are shown at a time.

Finally, add one more text field for "phone number" and a submit and reset button for the form.

<form action="script.php" method="post" title="Personal Information">
  ...
  <p>Phone Number
    <input type="text" name="phone">
</p> <p>
<input type="submit" name="submit" value="Send">
<input type="reset" name="reset" value="Reset"> </p>
</form>

The submit and reset buttons are both types of the input tag. Their "value" is the text that appears in the button. The value of the submit button gets included with the form data, but the receiving scripts can be programmed to ignore it based on the "name". The value of the reset button never gets sent along with form data. The button is used by the browser to clear data entered into the form without submitting it to the scripts or making any request to the web server.

All together, the form would look like this:

<form action="script.php" method="post" title="Personal Information">
<p>Your Name
<input type="text" name="name">
</p>
<p>Nickname
<input type="text" name="nick" value="no nickname">
</p>
<p> Short Bio
<textarea name="bio"></textarea>
</p> <p>What flavors of ice cream do you like?</p>
<p>
<input type="checkbox" name="icecream[]" value="vanilla">
Vanilla
<input type="checkbox" name="icecream[]" value="chocolate">
Chocolate
<input type="checkbox" name="icecream[]" value="strawberry">
Strawberry<br>
<input type="checkbox" name="icecream[]" value="other">
Other
<input type="text" name="other icecream">
</p> <p>If you could get a pet it would be a:</p>
<p>
<input name="pet" type="radio" value="no pet">
I do not want a pet <br>
<input name="pet" type="radio" value="kitten">
Kitten
<input name="pet" type="radio" value="cat">
Adult Cat
<input name="pet" type="radio" value="puppy">
Puppy
<input name="pet" type="radio" value="dog">
Adult Dog
<input name="pet" type="radio" value="bird">
Bird
<input name="pet" type="radio" value="fish">
Fish<br>
<input name="pet" type="radio" value="other">
Other
<input type="text" name="other pet">
</p> <p> State of Birth
<select name="birth state">
<option value="NC">North Carolina</option>
<option value="GA">Georgia</option>
<option value="SC">South Carolina</option>
<option value="TN">Tennessee</option>
<option value="VA">Virginia</option>
<option value="O">Other</option>
</select>
</p> <p>Phone Number <input type="text" name="phone">
</p> <p>
<input type="submit" name="submit" value="Send">
<input type="reset" name="reset" value="Reset"> </p>
</form>

 

Making The Form Accessible

In order for a form to be considered accessible, each input needs to be associated with some text. In the case of groups of radio buttons and check boxes, the group must also be formally tagged and represented by some text. The label tag can be used to associate text with a single form input and the legend tag can be used to associate text with a group wrapped by a fieldset tag. Out of the questions that already exist on the form, all of the text boxes and the select list are wrapped together with the associated question or text label with a "p" tag. Simply changing the paragraph (P) tag to a label tag makes those form inputs accessible.

Replace paragraph tags with labels tags for the text, text area, and select list inputs.

Next wrap a fieldset tag around the two paragraph tags that make the grouped inputs. The first paragraph can be converted to a legend tag.

The resulting form will look like this:

<form action="script.php" method="post" title="Personal Information">
<label>Your Name
<input type="text" name="name">
</label>
<label>Nickname
<input type="text" name="nick" value="no nickname">
</label>
<label> Short Bio
<textarea name="bio"></textarea>
</label> <fieldset> <legend>What flavors of ice cream do you like?</legend>
<p>
<input type="checkbox" name="icecream[]" value="vanilla">
Vanilla
<input type="checkbox" name="icecream[]" value="chocolate">
Chocolate
<input type="checkbox" name="icecream[]" value="strawberry">
Strawberry<br>
<input type="checkbox" name="icecream[]" value="other">
Other
<input type="text" name="other icecream">
</p> </fieldset> <fieldset> <legend>If you could get a pet it would be a:</legend>
<p>
<input name="pet" type="radio" value="no pet">
I do not want a pet <br>
<input name="pet" type="radio" value="kitten">
Kitten
<input name="pet" type="radio" value="cat">
Adult Cat
<input name="pet" type="radio" value="puppy">
Puppy
<input name="pet" type="radio" value="dog">
Adult Dog
<input name="pet" type="radio" value="bird">
Bird
<input name="pet" type="radio" value="fish">
Fish<br>
<input name="pet" type="radio" value="other">
Other
<input type="text" name="other pet">
</p> </fieldset> <label> State of Birth
<select name="birth state">
<option value="NC">North Carolina</option>
<option value="GA">Georgia</option>
<option value="SC">South Carolina</option>
<option value="TN">Tennessee</option>
<option value="VA">Virginia</option>
<option value="O">Other</option>
</select>
</label> <label>Phone Number <input type="text" name="phone">
</label> <p>
<input type="submit" name="submit" value="Send">
<input type="reset" name="reset" value="Reset"> </p>
</form>

Removing the paragraph tags changes the formatting of the form. For now this is not a concern, the formatting will be changed when CSS is applied.

Inside the fieldset groups, there is still text that needs to be associated with form inputs. Remove the remaining paragraph tags in the two fieldsets and wrap a label tag around each input tag and its accompanying text. The text "other" is shared by two inputs, one radio button and one text field. This will be corrected in the next step.

<form action="script.php" method="post" title="Personal Information">
... <fieldset> <legend>What flavors of ice cream do you like?</legend>
<label>
<input type="checkbox" name="icecream[]" value="vanilla">
Vanilla </label>
<label>
<input type="checkbox" name="icecream[]" value="chocolate">
Chocolate </label>
<label>
<input type="checkbox" name="icecream[]" value="strawberry">
Strawberry<br> </label>
<label>
<input type="checkbox" name="icecream[]" value="other">
Other
<input type="text" name="other icecream"> </label> </fieldset> <fieldset> <legend>If you could get a pet it would be a:</legend>
<label>
<input name="pet" type="radio" value="no pet">
I do not want a pet <br> </label>
<label>
<input name="pet" type="radio" value="kitten">
Kitten </label>
<label>
<input name="pet" type="radio" value="cat">
Adult Cat </label>
<label>
<input name="pet" type="radio" value="puppy">
Puppy </label>
<label>
<input name="pet" type="radio" value="dog">
Adult Dog </label>
<label>
<input name="pet" type="radio" value="bird">
Bird </label>
<label>
<input name="pet" type="radio" value="fish">
Fish<br> </label>
<label>
<input name="pet" type="radio" value="other">
Other
<input type="text" name="other pet"> </label>
</fieldset> ...
</form>

To correct the problem of two inputs sharing a text description, more text must be added. It can later be obscured by CSS if the label really isn't needed, but in most cases the one label per input is a good idea and makes form design more solid. In form design, exceptions are best handled by separate follow up questions. Move the "other" textfield input out of the fieldset, give it it's own text, and wrap the input and text with a label.

  <fieldset>
    ...
<label>
<input type="checkbox" name="icecream[]" value="other">
Other </label> </fieldset> <label> If other please specify <input type="text" name="other icecream"></label> <fieldset> ...
<label>
<input name="pet" type="radio" value="other">
Other
</label>
</fieldset>
<label> If other please specify <input type="text" name="other pet"></label>

Now the form is accessible. This example covers most of the formats of question commonly encountered. Fieldset tags can wrap more than just groups of radio buttons and check boxes. Any group with a common context could be handled with a fieldset. Consider the following form:

  <label>Height
<input type="text" name="height">
</label>
<label>Weight
<input type="text" name="nick" value="no nickname">
</label>
<label> Blood Type
<select name="birth state">
<option value="o-">O positive</option>
<option value="o+">O Negative</option>
<option value="a">A</option>
<option value="b">B</option>
<option value="ab">AB</option>
</select>
</label>

This form is perfectly accessible, but it's not perfectly clear. The logical assumption would be that the form is asking the user for their vital information, but perhaps that was not the author's intent. A fieldset can give these questions a clearer context without having to repeat a phrase or question in every label.

  <fieldset><legend>Your spouse's vital information.</legend>
     <label>Height
<input type="text" name="height">
</label>
<label>Weight
<input type="text" name="nick" value="no nickname">
</label>
<label> Blood Type
<select name="birth state">
<option value="o-">O positive</option>
<option value="o+">O Negative</option>
<option value="a">A</option>
<option value="b">B</option>
<option value="ab">AB</option>
</select>
</label> </fieldset>

Is less monotonous than:

  <label>Your spouse's Height
<input type="text" name="height">
</label>
<label>Your spouse's Weight
<input type="text" name="nick" value="no nickname">
</label>
<label>Your spouse's Blood Type
<select name="birth state">
<option value="o-">O positive</option>
<option value="o+">O Negative</option>
<option value="a">A</option>
<option value="b">B</option>
<option value="ab">AB</option>
</select>
</label>

Other ways to make form inputs accessible.

If design-wise it is not possible to wrap a label tag around both a form element and it's descriptive text, there is a work around. Tags in HTML have to be properly nested, so there are occasionally times where a label tag cannot wrap the text and the input tag. The most common case of this is table layouts, which should be avoided. CSS can replace the need for tables in most forms. If this isn't possible, assign the form input tag an "id" attribute, and use a matching "for" attribute in the label tag. The id attribute may not be shared with any other tag, even of a different type, in the same document.

<table>
  <tr>
    <td> <label for="unique_id">Text Label</label> </td> ....
  </tr>
  <tr>
    <td> <input id="unique_id"> </td> ....
  </tr>
</table>

Fieldset legends cannot use the same "for-id" paradigm. They must appear in their fieldset, and should be before any text or other tags.

It is important to validate HTML documents. This helps to ensure that they will behave predictably in different browsers. While there is no guarantee of this, validation can sometimes make a subtle or not so subtle difference in older or less tolerant browsers. If you validate the accessible form, you will (should) be informed that the textarea tag requires both the "cols" and "rows" attribute indicating how many characters wide and lines tall it should be. This infringement doesn't break the form in any of the common browsers, but there may be one browser out there that does not handle this exception so gracefully. Validating a document can sometimes help debug an unruly page, especially when CSS styles are not behaving as expected or according to known bugs.

Sometimes accessibility problems arise in a web form that have nothing to do with the HTML. At the bottom of this "accessible form" is a question asking for a phone number. If this input field were required or even just important, it might cause problems. Suppose a user cannot talk on a normal phone. How will they inform the recipient of this data? There is no field for comments. They could add this information to the "bio", but that probably would not be appropriate. Suppose the phone number field is limited to 12 characters. This is more than enough for most phone numbers, but not enough for international numbers, and certainly not enough space for a phone number and a friendly note that the person can only be reached via TTY.

The important thing to realize from this scenario is that restrictions and requirements on web forms should be carefully considered. The whole point of a web form is to automate a process. In some cases the best way to handle exceptions may be providing a fall back, such as a comments field. This is a very useful tactic in handling un-anticipated barriers or problems.

 

Styling The Form

There is a very important reason this tutorial far has been very (HTML) source code oriented. CSS applies style rules to tags. Without understanding the tags that make up a document it is impossible to effectively style it. CSS can be used to customize the default formatting of tags such as to change the default font-family, size, or color. These formatting changes don't necessarily require an in depth knowledge of HTML. CSS is more than just making small changes to content format, it makes complete face lifts possible with just a few nips and tucks.

The form with paragraph tags separating form inputs, and the accessible form look different because they are made of different tags. This does not have to be the case. By applying some simple CSS, the accessible form can be made nearly identical to the original version:

Inside the style tag, in the head, add the following:

  label{ 

    display:block; 
    margin-top:1em; marign-bottom: 1em;
  }

fieldset{ display:inline; border:none; margin-left:0; padding-left:0; } fieldset legend{ padding-left:0; padding-top: 1em; margin-left:0; margin-bottom: 0.65em; }
fieldset label, fieldset input{display: inline;}

label.hidden{ display: block; visibility:hidden; margin-top: -2em; }
label.hidden input{ visibility:visible; margin-left: -5em;}

This short style sheet formats the accessible form to almost exactly the same format at the original form.

How These Styles Work

The first style:

  label{ 
    display:block; 
    margin-top:1em; marign-bottom: 1em;
  }

Sets a style rule that makes label tags act more like paragraph tags. The "display" property changes the label tag's display style from "inline" to "block". This effectively draws an invisible box around the label tag to separate itself from other inline tags. Inline tags tend to flow together horizontally and can't have certain attributes, such as a height or width set. Blocks on the other hand tend to fall to new lines, stacking vertically. The "margin-top" and "margin-bottom" properties add a buffer zone to the top and bottom of the label tag's block much the same way paragraphs have a line of buffer between them and other elements.

The next style:

  fieldset{ 
    display:inline; 
    border:none; 
    margin-left:0;
    padding-left:0;
  }

Changes the way the fieldset tag acts. In the original form there was no tag wrapping the question and choices, so to make the accessible form look as much like the original version as possible the extra tag needs to be amorphous, like an inline tag. By default, fieldsets have a border so this is removed. Margins at the top and bottom are preserved, but the padding and margins on the left are removed to eliminate the indenting effect that the fieldset has on the tags inside.

  fieldset legend{
    padding-left:0; padding-top: 1em; 
    margin-left:0; margin-bottom: 0.65em; 
  }

This rule set looks different because it does not apply to all tags of one type the way the first two did. CSS rules sets are made of two components, a selector that specifies what the rules apply to, and a rule list. The selector comes before the pair of curly brackets, and the rule list is contained inside. Each rule starts with a property followed by a colon, and then one or more values to set the property followed by a semi-colon.

The rule list above applies to only legend tags that appear inside fieldset tags. Because fieldset is now inline, the spacing that separates it from the elements above has to come from something inside at the top that is block formatted. Paddings and margins work differently. When setting margins fail, padding may give the desired effect. Legend tags are already block style, so that property does not need to be set. The left padding and margin are removed to eliminate the indenting typically applied to fieldset legends, and a margin on the bottom is added to space it from the form inputs below.

  fieldset label, fieldset input{display: inline;}

label.hidden{ display: block; visibility:hidden; margin-top: -2em; }

There are several shorthand notations in CSS. Selectors can be combined in a list by comma separating them. This works well when two tags need the same or similar rules. Above, labels and input tags that appear inside of a fieldset tag are set to the inline format.

The rule that follows uses another type of selector, classes. Setting the "class" attribute of a tag, allows it to be targeted by CSS without effecting other tags of the same type unless their class also matches. As an added bonus, rules that are more specific take precedence over more general rules, this is where the "cascading" part of the name "cascading style sheets" comes from. Rules can be written for general cases and overridden in more specific cases. This allows style sheets to be shared widely among many different pages, but add specialized rules for greater flexibility.

Keep in mind that it is not the "class=hidden" that makes the tag disappear, it is the style assigned to that class. The class is just a name and does not affect the style itself.

Label tags with the class "hidden" flow as a block, but are not visible. This means the tag takes up space, but cannot be seen. This may not be the best choice for making the label accessible, since depending on the browser implementation it may also be hidden from a screen reader. Alternatives to this method will be covered later. The last property, a negative top margin, is a trick to make the input tag appear to come up to the previous line. Remember that blocks go down one line. If this label was inline it would line up horizontally beside the preceding fieldset, which is also inline. This would cause the input box be in the right ertical position, but stick too far out.

  label.hidden input{ visibility:visible; margin-left: -5em;}

The last rule set applies to to input tags that are inside labels with the "hidden" class. It makes them visible, overriding the hidden nature of the enclosing hidden label. Again a negative margin is used, this time to make up for the extra space taken up by the invisible label tag.

To make the styled accessible form look like the original, the class must be applied to the two label tags for "If other please specify".

  </fieldset>
<label class="hidden"> If other please specify <input type="text" name="other icecream"> </label>
<fieldset> ...
</fieldset>
<label class="hidden"> If other please specify <input type="text" name="other pet"> </label>
<label> State of Birth ...

The Value of Styles

This six rule set style sheet is relatively simple because it only applies to a few tags. At the same time, it is a little complex because it completely changes the nature of several tags. Style sheets are powerful but this exercise begs the question, "Was all that work worth the effort to make an accessible form look exactly like the original? "

The answer is, "Probably". There are several ways in which style sheets pull their own weight. Now that this style sheet has been written it can be used not only on this form, but on many others as well. The work of writing a style sheet is often justified when there is potential to re-use it for other applications. Style sheets are easy to share. To make the style sheet sharable:

  1. Cut and paste all the rule sets out of the style tag into a separate file.
  2. Name the file and give it the extension .css.
  3. In the style tag write the line "@import "yourfile.css";
    • Or outside of the style tag add a link tag :
<link rel="stylesheet" href="yourfile.css" />

Style sheets can govern an entire layout, cutting the amount of code used in the body of a document by half or more compared to table layouts. Style sheets can also do things that tables cannot. Shared style sheets compound this saving because the style sheet can be loaded once and cached. Table layouts clog the code of every page they are used on.

CSS can also degrade more gracefully. Without implementing a complex scripted templating system there is no way to create a table layout that looks sleek in the modern browser, clean in older browsers, and perfectly formatted for printout. Because CSS styles are not embedded in the markup of the document's body, they are easy to swap out. Multiple versions of one style sheet can be applied automatically or at the user's discretion to optimize the appearance of each page for each user.

The true value of CSS is control over the appearance of content, control over both consistency and change.

 

Deck the Form

For the final exercise in this tutorial, the form will undergo a drastic metamorphosis. This is more along the lines of other flashy CSS demos. By adding strategic markup and then styling it with CSS, the form will go from bland to bold.

Adding Markup

While it may be possible to work with the markup already on the page, for maximum flexibility some additional tags will be added. There are two types of tags used for style specific markup. These tags have no real semantic meaning and are the only tags that should be used for styling. Before employing any other HTML tag for layout control, consider carefully the consequences.

In the previous example some tags were inline format and others were block. HTML 4.0 and XHTML 1.0 have two tags dedicated to styling. The "span" tag is by default an inline tag. The "div" tag is a block tag by default. These tags can have their properties changed just as with any other tag, but in most cases it is least complex to use the tag already best suited for the job.

Using div tags, the screen can be divided into columns, rows, and other forms of boxes. These boxes can be nested and one popular technique is to nest boxes to make complex and controlled designs. Applying too many styles to any one tag can cause problems, so most designers prefer to split up the work load.

Nest the "h1" and "p" tag at the top of the body with two div tags. Set the outside tag's id attribute to "topleft" and the inside tag's id attribute to "topright".

  <body>
<div id="topleft"><div id="topright>
<h1>An accessible form made attractive with CSS</h1>
<p>Please fill out all required fields,
any additional information that is applicable,
and press the send button.
</p>
</div></div> ...

Next nest the form tag the same way with div tags with the ids: "formleft" and "formright".

<div id="formleft"><div id="formright>
<form action="script.php" method="post" title="Personal Information">
...
</form>
</div></div>

Wrap four div tags around four sections of the form: the first three text fields, the ice cream question, the pet question, and the rest. id the divs, "one", "two", "three" and "four" respectively.

...
<form action="script.php" method="post" title="Personal Information">
<div id="one"> <label>Your Name
... </div> <div id="two"> <fieldset> <legend>What flavors of ice cream do you like?</legend>
... </div> <div id="three"> <fieldset> <legend>If you could get a pet it would be a:</legend>
... </div> <div id="four"> <label> State of Birth ...
</div>
</form>

Finally apply a span tags around the text portion of the labels with "class=hidden".

  </fieldset>
<label class="hidden"><span>If other please specify</span> <input type="text" name="other icecream"> </label>
<fieldset> ...
</fieldset>
<label class="hidden"><span>If other please specify</span> <input type="text" name="other pet"> </label>
<label> State of Birth ...

Notice how none of these tag affects the appearance of the page. These unstyled tags blend in perfectly to the existing style sheet.

More Styles to Choose From

This time around the style sheet will change more than just margins and display properties. Remove the existing styles and then apply a drastic change by styling the body tag with the following style:

  body{
background: #000 url(stylesheet/stylesheet2.jpg) top left repeat-y;
margin: 0;
padding: 0;
color: #FFF;
font-family: Geneva, Arial, Helvetica, sans-serif;
}

This rule set changes the background-color property to black and runs a background image down the left side. The background property is a shorthand allowing the change of any and all background properties, such as background-color, background-image, and background-position, all in one line. Another shorthand used in this rule is the abbreviated color, #000. In CSS 2 color hex codes can be abbreviated if both digits for all three colors are matched. #000000 can be written as #000, #FFFFFF as #FFF, #CC0000 (NC State Red) as #C00, and so forth. By default the body tag as a margin and padding, which many designers choose to remove.

The color property refers to the color of the text. Font-family can be changed in the body tag, applying the selected font to every other tag, except the "pre" (preformatted text) tag and a few others.

One caveat of to note, the only way to make a background image repeat from top to bottom of a page is to apply it to the body tag. There are currently no other techniques that force a background image, or even an absolutely positioned image, to align with the bottom of the page. To date, only Opera 8 features the ability to position based on the bottom of the document. Other browsers align to the bottom of the window which is the behavior of Mozilla, Safari, and IE.

  #topleft h1, #topleft p{
background: url(stylesheet/stylesheet.jpg) top left repeat-y;
padding-left: 20px;
}

Even the backgrounds of tags such as the "h1" and the "p" can be styled. This can be used to help draw divisions between sections, or add subtle shade. The above rule sets only apply to h1 and p tags found inside the div with the id "topleft". Just like assigning styles to classed tags, tags with ids can be targeted with CSS too. While classes are usually selected by the notation, "tagname.class" they can also be selected by "*.class" or ".class". The first notation has the best support among browsers, bugs in some browsers occasionally skip the latter two notations. For tags with an id assigned the selection notation is "tag#id", but because an id can only be assigned to one tag "#id" is more commonly used and is well supported. Later tutorials will cover CSS selectors more in

  #formleft{
background: url(stylesheet/stylesheet2.jpg) top left repeat-y;
padding-left: 130px;
}
#formright{
background: url(stylesheet/stylesheet3.jpg) top right repeat-y;
float: left;
width:100%;
}
#topright{
background: url(stylesheet/stylesheet3.jpg) bottom right no-repeat;
}

The tags that were id'd as "formleft" and "formright" are assigned backgrounds. Since no color is specified the backgrounds from tags that precede these two will "show through" any portions of these tags that are not covered by the background image. Background images can be layered like decals to create complex appearing designs. Until IE7 comes out there are limitations to the creativity that can be used since transparent PNG support has always been lacking in IE. Background images can align to sides of the containing box: top, bottom, left, right, and center. These can be used in combinations, and pixel, em, and percentages (from the top or from the left) can also be used if position is desired somewhere between the key points. Background images can scroll with the content or appear to be "fixed" in place with the content scrolling above it. Background images can also be tiled with repeating in both directions, only horizontally, or only vertically.

The two rule sets above do more than just apply background. The padding-left property pushes content inside the "formleft" tag to the right, preventing it from appearing on top of the background image. This style is applied here because the rest of the tags inside are "floated". Floating is a powerful formatting tool that CSS provides, but it can cause problems when combined with too many other property changes in the same tag.

The tag with the id "formright" is inside "formleft" and floated to the left. This means that it will try to line up horizontally with other elements that appear before it as long as there is room but will go down a line and move to the far left if there isn't room on the current line. Floating makes block elements behave like inline elements in some ways, but allows them to retain the advantages of being block, such as control over height. Floating is extremely useful, but also extremely tricky to work with. It has poor support in older browsers and comes with some extra restrictions. Floated tags must have a set width. This can be in pixels, percents, ems, or any other unit, but it must be set. Floating blocks cannot automatically set their widths the way normal blocks can. Failing to set width in a float will cause it to behave unpredictably.

Another limitation of floats is that they tend to "pop-out" of non-floating tags they appear inside of. This causes the containing tag to appear deflated. To see this effect try removing the background property from the body tag. Notice how even thought the "formleft" tag contains the "formright" tag, the left hand background image doesn't stretch vertically the way the right handed background does. This shows why the background for the body tag is needed, but also shows that the background for the "formleft" tag is now useless.

  #topleft p{ margin-bottom:0;}			
form{float: left; width: 100%;}

Even after being floated, block elements will respect the margins of other tags. To get rid of extra spacing, the bottom margin of paragraph tags only in the "topleft" tag is removed. The "formright" tag above was floated because it need to float to avoid being deflated. The divs inside the form need to float, and so anything that contains them must also be floated or face the deflating effect. The form tag is floated left and so it's width must also be set.

  #one, #two, #three, #four{
float: left;
width: 300px;
height: 300px;
padding: 10px;
}

Now the previous floats become important. With the four form input containers floated, the layout of the page changes drastically. Depending on the width of the browser window the form will now show the form elements as a row of 4, 3 and 1, 2 by 2, or a column of 4.

Try removing the width and height and see what happens. Some browsers will handle this more gracefully than others, but floats with no width can cause major problems. Try removing the widths on the "formright" and form tags.

With the widths restored, the final bits of style give each dividers a distinctive look:

  #one{
background:#190000 url(stylesheet/div1.gif) bottom right no-repeat;
border: 3px solid #300;
border-top: 0;
border-left: 0;
}
#two{
background:#101010 url(stylesheet/div2.gif) bottom right no-repeat;
border: 3px solid #222;
border-top: 0;
border-left: 0;
}
#three{
background:#000019 url(stylesheet/div3.gif) bottom right no-repeat;
border: 3px solid #003;
border-top: 0;
border-left: 0;
}
#four{
background:#001900 url(stylesheet/div4.gif) bottom right no-repeat;
border: 3px solid #030;
border-top: 0;
border-left: 0;
}

In addition to the above style sheet, the styles from the previous tutorial can be layered to make the page look even better. Above the style tag add a link tag to the first style sheet:

  <title>An accessible form made attractive with CSS</title>
<link rel="stylesheet" href="stylesheet.css"/>
<style type="text/css"> ...

Now the form has both style sheets applied. If a copy of Netscape 4 is available, try the page in that. It looks horrible. It's often a good idea to hide more complex style sheets from older browsers, especially the ones with partial CSS support.

Create a new stylesheet file and cut/paste the new style sheet (just the contents of the style tag) into it. Use the @import rule to include this style sheet.

  <style type="text/css">	 
  @import "stylesheet2.css";
  ...

This is one way to gracefully degrade your style sheet. The link tag was a feature of CSS 1, but the @import rule was not added until version 2. This means that browsers with no CSS2 support won't see styles hidden by an import.

Accessibility Options

In the previous, more plain, form a tag was hidden to make the accessible form look just like the original. Hiding this text was not necessary. The text was useful and probably contributed just as much to usability as to accessibly. Suppose that hiding this tag by changing the display property confused a screen reader. How else can this text be styled so that it won't appear?

Another trick is to move a tag "way off screen". Unless the tag contains a lot of content, this trick will allow a screen reader to see the text (because it doesn't care about screen positions) but the text would never appear on screen. On top of the two shared style sheets, add another layer of CSS to the document:

  <style type="text/css">	 
  @import "stylesheet2.css";

  label.hidden span{
position: absolute;
top: -999px;
left: -999px;
}
label.hidden{
display: block;
visibility:visible;
}
label.hidden input{ visibility:visible; margin-left: 7em;}

These three rules override the rules for "label.hidden" and "label.hidden input" in the linked css file and add a new rule. All together they unhide the label tag, move the span around the text off-screen, 999 pixels above the top of the window and 999 pixels to the left. The input box is moved to the right with a normal margin rather than to the left with a negative one since it no longer has to follow the text portion of the label. The text is taken out of the display of the page all together, but still exists off screen.

Absolute positioning is another format model that allows complete control of where a tag appears. It is often used to create columns or move navigation to the top of a page when it appears after content in the HTML. Absolute positioning has a trade off just as all formatting models do. By moving a tag somewhere else on the screen, it's ability to wrap around other tags is taken away. Absolutely positioned tags can cover up other tags if the formatting isn't carefully applied. Absolutely positioned tags can expand their size based on their contents, but they cannot push other tags down out of the way.

The final version of the form does not look much different than hthe previous version, but is probably more accessible.

Conclusion

CSS can have a sharp learning curve. Even after working with it extensively there are always new applications of the properties to discover. CSS is about control. It allows the designer to provide a consistent look on multiple pages. Style sheets can be modular so that every page has some styles and various sub-sets have their own customizations. In this way change is easier to deploy because than appearance of a document is controlled by an external factor, one that can be single sourced.

The resources page has many links to CSS resources. Floatorial is an excellent way to learn about positioning. Trial and error, and learning by example are just two great ways to develop CSS skills. The benefits out weigh the investments, style sheets are here to stay and with the proliferation of XML and mobile devices the old ways of designing pages will not sustain dynamic sites for much longer.

 

 
 

 
 

Getting It All, With CSS

Part 1
Printer Friendly:
1.1 1.2 1.3 1.4 1.5

Part 2
(February 2005)

Part 3
(Jan/Feb 2006)

Other articles

The Year of the
Cascading Style Sheet