Friday, May 18, 2007

Styling form controls

A question that is frequently asked in forums like the css-discuss mailing list is how to style form controls in a consistent way across platforms. Most of the time, the question is asked by someone who has just tried to do that, and noticed the difference in rendering across browsers and operating systems.

The short answer is probably disappointing to many: you can’t. Some also argue that you shouldn’t, since doing so may reduce usability. My opinion on that is that light, sensible styling of some form controls can be OK, as long as you don’t overdo it. But what if we don’t think about usability, and just want to see what actually can be styled? I’ve made a few examples that make up a longer answer to the question about styling form controls.

There are a lot of controls that can be used in an HTML form. For this exercise, I applied styling to the submit button (), the menu, a.k.a. the select box (), the single line text input (), the checkbox (), the radio button (), and the file select control ().

I created three five six simple documents, each containing twelve controls of the same kind. Then I created a different CSS rule for each element. Due to the various controls having different properties to style, I made two three slightly different sets of rules.

The following rules were applied to submit buttons, select boxes, single line text inputs, and file select controls:

#el01 {color:#00f;}
#el02 {background-color:#ddd;}
#el03 {color:#fff; background-color:#33b;}
#el04 {border-width:4px;}
#el05 {border-color:#00f;}
#el06 {border:0;}
#el07 {font-family:"Courier New", Courier;}
#el08 {font-size:150%;}
#el09 {font-size:10%;}
#el10 {font-weight:bold;}
#el11 {padding:0;}
#el12 {margin:0; text-align:right;}
For the select boxes and submit buttons I changed the last rule a bit to make sure any effect of text-align is visible:

#el12 {margin:0; text-align:right; width:10em;}
Checkboxes and radio buttons were styled with these rules:

#el01 {color:#00f;}
#el02 {background-color:#ddd;}
#el03 {color:#fff; background-color:#33b;}
#el04 {color:#fff; background-color:#33b;}
#el05 {border-width:4px;}
#el06 {border-color:#00f;}
#el07 {border:2px solid #999;}
#el08 {width:40px; height:40px;}
#el09 {font-size:150%;}
#el10 {font-size:10%;}
#el11 {padding:0;}
#el12 {margin:0;}
I kept the styling very basic in order to clearly show the effect each rule has on styling in the various browsers. There are of course many more styles that could be added, like width, height, background images, and different border styles, but I had to draw the line somewhere. When the rules were set up, I loaded the documents in the following browsers:

Camino
Firefox 1.0 PR Mac
Firefox 1.0 PR Win
IE 5 Mac
IE 6 Win
Opera 7.53 Mac
Opera 7.53 Win
Safari
All Mac browsers were running on Mac OS X 10.3.5, and all Windows browsers were tested in Windows 2000 and Windows XP. By default, this is what the various controls look like in each of the tested browsers:

Prettier Accessible Forms


Prettier Accessible Forms

It can be time consuming to make web forms both pretty and accessible. In particular, laying out forms where the form label and input are horizontally adjacent, as in the image below, can be a real problem. We used to use tables, which worked well in this scenario—but forms don’t constitute tabular data, so it’s a semantic faux pas.

I’ve tried to create a form-styling solution that is both accessible and portable (in the sense that I can move the code from one project to the next). Floats have often provided a solution to my problem, but given the complexity of some layouts and the numerous float bugs associated with Internet Explorer, it’s not always easy to reuse a float solution. I wanted to create something that anyone could easily reuse on any project: a style sheet that, when applied to a correctly marked up HTML form, would produce the basis of the required layout. So here it is—my attempt at portable, accessible forms.



Marking up the form
The most important part of a form is the HTML we use to build it. Fortunately, HTML gives us a nice assortment of tags to build our forms in an accessible way. These are fieldset, legend, and label. If you are unfamiliar with these tags, here’s a brief overview:

fieldset and legend
The fieldset element allows us to group form controls into logical, related “chunks.” legend then allows us to add a caption to that fieldset, which helps users understand the context of the form controls contained within that fieldset. In some screen readers, the legend is associated with each form control within a fieldset and is read out after each tab of the keyboard, so that a particular control can always be referenced back to its legend.

label
The label element is used to associate information with a specific form control, while also enforcing a code-level association between form control information and the control element itself.

Let’s look at a simple fieldset example (line wraps marked » -Ed.):


Delivery Details



























  1. Is this address also your invoice »
    address?*







The HTML is fairly simple, but you will notice a few things in the structure. I’m using an ordered list (ol) inside the main fieldset. I’m doing this for two reasons:

I can use each list item (li) as a container for each row in the form, which is handy for styling.
It is, in my opinion, semantically appropriate (i.e. a list of form controls in some kind of logical order).
Additionally, the ol provides additional information for some screen readers that announce the number of list-items when they first encounter the list.

Fields that have two or more control options are nested inside an additional fieldset. This logically groups the control options, as discussed above, and the legend acts as a caption for each option within (in our case, radio inputs). Each option is then wrapped inside its own label tag. This is the most accessible approach, and really aids users of assistive technologies.

Styling the form
The styling of the form is the fun part. My aim was to produce a main forms style sheet that can be imported to give a form the basic structural styling we need. Here it is.

form.cmxform fieldset {
margin-bottom: 10px;
}
form.cmxform legend {
padding: 0 2px;
font-weight: bold;
}
form.cmxform label {
display: inline-block;
line-height: 1.8;
vertical-align: top;
}
form.cmxform fieldset ol {
margin: 0;
padding: 0;
}
form.cmxform fieldset li {
list-style: none;
padding: 5px;
margin: 0;
}
form.cmxform fieldset fieldset {
border: none;
margin: 3px 0 0;
}
form.cmxform fieldset fieldset legend {
padding: 0 0 5px;
font-weight: normal;
}
form.cmxform fieldset fieldset label {
display: block;
width: auto;
}
form.cmxform em {
font-weight: bold;
font-style: normal;
color: #f00;
}
form.cmxform label {
width: 120px; /* Width of labels */
}
form.cmxform fieldset fieldset label {
margin-left: 123px; /* Width plus 3 (html space) */
}
As you can see, the styles are pretty basic; those with a keen eye will notice the display property set to “inline-block” on the labels. If you are unfamiliar with “inline-block,” here’s an explanation from the W3C site:

This value causes an element to generate a block box, which itself is flowed as a single inline box, similar to a replaced element. The inside of an inline-block is formatted as a block box, and the element itself is formatted as an inline replaced element.

This is the magic, and the good news is that it works in Internet Explorer for both Windows and Mac. If you are tempted to use this value in other scenarios, I must point out that in Internet Explorer for Windows, it only works on elements that have a default display of “inline,” which a label does. The bad news, however, is that Mozilla-based browsers (Firefox, Netscape, etc.) do not directly support this property, but we can fix it, and I’ll come to that shortly.

So, these are the core styles required to give the form its most basic appearance.

I wanted to create a style sheet that contains basic form styles that act as part of a larger library of reusable style rules. In theory, they would not need to be modified by an author, but could simply be included in any site to set the baseline rules. (This core set of form styles is the first part of my vision for creating a library of style sheets that handle the common CSS conundrums.) The best part is that authors who want to modify something like the width of the label elements, can easily overwrite the default further down in the cascade or with a more specific selector. And to truly customize each form, you can add your own styles in a separate style sheet like I have done in this “pretty” form example.

Bugs
As I mentioned above, users of Mozilla-based browsers won’t see what all the fuss is about. Unfortunately, Mozilla does not currently support the “inline-block” display type, which is a bit of a problem. However, Mozilla has a browser-specific display value, “-moz-inline-box”, which acts, for the most part, like “inline-block.” The problem with this value is that if you have a really long label, the text disappears under the adjacent form control. Text does not wrap inside an element displayed as “-moz-inline-box.” But if we place the label text inside an element displayed as “block” inside the “-moz-inline-box” element and give it a width, it behaves as it should.

Adding all that by hand into the document is going to mess up our nice, lean, mean HTML —plus we may decide to change the form layout later, and who wants the extra markup in there? Luckily, there’s an easy way to fix this using JavaScript and the DOM (line wraps marked » -Ed.):

if( document.addEventListener ) »
document.addEventListener( 'DOMContentLoaded', cmxform, false);

function cmxform(){
// Hide forms
$( 'form.cmxform' ).hide().end();

// Processing
$( 'form.cmxform' ).find( 'li/label' ).not( '.nocmx' ) »
.each( function( i ){
var labelContent = this.innerHTML;
var labelWidth = document.defaultView. »
getComputedStyle( this, '' ).getPropertyValue( 'width' );
var labelSpan = document.createElement( 'span' );
labelSpan.style.display = 'block';
labelSpan.style.width = labelWidth;
labelSpan.innerHTML = labelContent;
this.style.display = '-moz-inline-box';
this.innerHTML = null;
this.appendChild( labelSpan );
} ).end();

// Show forms
$( 'form.cmxform' ).show().end();
}
The JavaScript uses the wonderful JQuery library (which also, obviously, needs to be included) to simplify the processing. I will briefly explain how this works.

Firstly, I hide any form that uses the “cmxform” class.

// Hide forms
$( 'form.cmxform' ).hide().end();
We do this because otherwise the user might see the form “fixing” itself as it renders in the page, which can look a bit strange.

Secondly, using the JQuery methods and a combination of CSS selectors and XPath, I collect all labels that are a direct descendant of an li, that do not have a class of “nocmx”.

$( 'form.cmxform' ).find( 'li/label' ).not( '.nocmx' ) »
.each( function( i ){
...
The reason I use the “nocmx” filter is so that users can add that class to labels that require a different styling. This can be very useful, as I have discovered from using this method for a while. Then, for each collected label, a span is created inside to fix the “inline-block” problem.

$( 'form.cmxform' ).find( 'li/label' ).not( '.nocmx' ) »
.each( function( i ){
...
}
Finally, all the originally hidden forms are made visible again, and everything looks sweet.

// Show forms
$( 'form.cmxform' ).show().end();
Note: I’m using the Mozilla-specific document.addEventListener() method to launch the script. This really is ideal, as it only runs for Mozilla (which is all we need) and it launches as soon as the DOM has been loaded.

Although JavaScript might not appear the most elegant solution, it is completely unobtrusive and, when JavaScript is disabled, the form degrades gracefully.

There’s also a small amount of tidying up to do in Internet Explorer though. For Windows, we need to tweak the positioning of the legend@s so they line up neatly. This can be achieved by giving the @legend a negative left/right margin as shown below:

form.cmxform legend {
padding: 0 2px;
font-weight: bold;
_margin: 0 -7px; /* IE Win */
}
For IE5/Mac, we need to tweak the display of the legend, to fix an odd display bug, by adding the following:

/*\*//*/
form.cmxform legend {
display: inline-block;
}
/* IE Mac legend fix */
This rule allows us to supply a rule specifically to Internet Explorer for Mac. If you are uncomfortable in using browser specific rules in this way, feel free to remove them.

You could add these fixes to browser-specific style sheets, but I wanted this technique to be as portable as possible, so all the styles are in one place.

Finishing up
We’re done. All you need to do is include the relevant “cmxform” files and then add the class of “cmxform” to any form you need to. (If you are wondering where the name “cmxform” came from, it’s there because I developed this technique while working for Cimex Media in London.) Enjoy!

Note: This form technique has been tested with Safari 2.0.3, Firefox 1.5, Opera 8.5, Internet Explorer 7b2 , Internet Explorer 6, Internet Explorer 5 (Windows), Internet Explorer 5.2 (Macintosh), Netscape 7.2 (Macintosh), and Netscape 8.1 (Windows

CSS Forms

CSS Forms

Form layout

Semantically speaking, should we be using tables to lay out forms, or should we be using some other mark-up combined with CSS? Responding to this question, Drew McLellan comments on Russell Beattie’s Notebook:
I’m comfortable using tables for forms. My point of view is that they are interactive tabular data.

If you mark up your labels in a th, your form controls in a td and stick them both in the same row, you can justifiably represent these name/value pairs as a table. But, of course, that’s not the end of the story. What if you don’t want your labels next to your form controls? My contact form, for example, has labels sitting above the form controls.

Because you’ve just decided that your name/value pairs can and should go in a table, you have inherently defined how your form should look. Forms engage the user directly – more so than any other part of a website – how they are presented is extremely important. So although one can justify laying out a form in a table, it’s simply not flexible enough. Which begs the question: what mark-up should we use instead?

What we really need is some block level mark-up (to be compliant with XHTML Strict) which meaningfully associates the form control with its preceding label. And I reckon HTML 2.0 provides just the thing.

Enter the little-used definition list. By placing the label in a dt (definition term) element and the form control in a dd (definition definition) element, we can meaningfully associate one with the other. Consider this simple example:



Email:


Name:



If the side-by-side table layout is what you’re after, we can apply some simple styles, based upon Mark Newhouse’s superb ALA article, Practical CSS Layout.

FORM DT {
clear:both;
width:33%;
float:left;
text-align:right;
}

FORM DD {
float:left;
width:66%;
margin:0 0 0.5em 0.25em;
}
There will be those of you out there who say you can’t use a definition list for a form – it’s not a list of definitions. I would rebut with this: the HTML 4.01 specification says that a dl could be used for pairings other than definitions, citing a script (character/speech pair) as an example.

Using a dl is more flexible than tables, and lighter & more meaningful than divs or paragraphs. It’s what I’ll be using for all my forms in future. Update: Here’s a worked example.

Super simple CSS bars



Html:
code of XHTML




Stylesheet:

div.progress-container {
border: 1px solid #ccc;
width: 100px;
margin: 2px 5px 2px 0;
padding: 1px;
float: left;
background: white;
}

div.progress-container > div {
background-color: #ACE97C;
height: 12px
}

Basic CSS Bar Graph


Basic CSS Bar Graph


Having a working knowledge of XHTML and CSS when developing applications is a big help in knowing what can be done client-side and what should be generated server-side.

Recently we’ve had to tackle some interesting visualizations which we coded in XHTML and CSS. The method we used, while fairly simple, was a big help to the engineer and created a very flexible and inexpensive solution. We thought we would share our solution and code in case anyone else ran against similar situations.

Update
I posted a live example page with everything in tact. So far I’ve only been able to test in Firefox 1.0.7, Firefox 1.5, IE 6, Safari 1.3.3, and Opera 9(TP1). You can view it here.

Basic CSS Bar Graph
This is a simple bar graph we developed for a tool we’re releasing shortly for our client. The concept is simple, utilize the percentage width abilities of CSS to accurately portray a percentage bar graph.

http://applestooranges.com/webresources/images/posts/graph1.gif



24%

CSS Diagrams, Bar Graphs, Star Rater

Creating a graph using percentage background images


  • 20%

  • 40%

  • 60%

  • 80%

  • 100%



ul.graph
{
margin: 0;
padding: 0;
list-style-type: none;
}

ul.graph li
{
margin-bottom: .5em;
padding: .2em;
background: #600;
color: #fff;
}

ul.graph li.percent20
{
background: url(graph20.jpg) repeat-y 20% 0;
}

ul.graph li.percent40
{
background: url(graph40.jpg) repeat-y 40% 0;
}

ul.graph li.percent60
{
background: url(graph60.jpg) repeat-y 60% 0;
}

ul.graph li.percent80
{
background: url(graph80.jpg) repeat-y 80% 0;
}