CSS complex forms

Complex forms with CSS can be quite difficult to stylize because of the many existing discrepancies across browsers. Let's say that we want to stylize a form for ordering books. We could start with a markup like this:

<div id="order">
<h2>Order your books</h2>
<form action="#" method="post">


<table summary="Order: copies, code, title, price">

<tr>
    <th scope="col">Copies</th>
    <th scope="col">Code</th>
    <th scope="col">Title</th>
    <th scope="col">Price</th>
</tr>

<tr>
    <td><input type="text" name="copy1" id="copy1" /></td>
    <td><input type="text" name="code1" id="code1" /></td>
    <td><input type="text" name="title1" id="title1" /></td>
    <td><input type="text" name="price1" id="price1" /></td>
</tr>


<tr>
    <td><input type="text" name="copy2" id="copy2" /></td>
    <td><input type="text" name="code2" id="code2" /></td>
    <td><input type="text" name="title2" id="title2" /></td>
    <td><input type="text" name="price2" id="price2" /></td>
</tr>



<tr>
    <td><input type="text" name="copy3" id="copy3" /></td>
    <td><input type="text" name="code3" id="code3" /></td>
    <td><input type="text" name="title3" id="title3" /></td>
    <td><input type="text" name="price3" id="price3" /></td>
</tr>

<tr>
    <td><input type="text" name="copy4" id="copy4" /></td>
    <td><input type="text" name="code4" id="code4" /></td>
    <td><input type="text" name="title4" id="title4" /></td>
    <td><input type="text" name="price4" id="price4" /></td>
</tr>




</table>


<fieldset>
<legend>Payment method</legend>

<ul>
    <li>
        <label for="cod">COD</label>
        <input type="checkbox" name="cod" id="cod" value="cod" />
    </li>
    <li>
        <label for="visa">VISA</label>
        <input type="checkbox" name="visa" id="visa" value="visa" />
    </li>
    <li>
        <label for="american-express">American Express</label>
        <input type="checkbox" name="american-express" id="american-express" value="american-express" />
    </li>
    <li>
        <label for="master-card">Master Card</label>
        <input type="checkbox" name="master-card" id="master-card" value="master-card" />
    </li>
    
</ul>

<div class="footer">

    <div class="left">
    
        <label for="cc-number">N.</label>
        <input type="text" name="cc-number" id="cc-number" />
    
    </div>
    
    <div class="right">
    
         <label for="cc-expires">Expires</label>
         <input type="text" name="cc-expires" id="cc-expires" />
    
    
    </div>


</div>

</fieldset>

<ul class="customer-info">

    <li>
         <label for="name">Name</label>
        <input type="text" name="name" id="name" />
        <label for="address">Address</label>
        <input type="text" name="address" id="address" />
    </li>
    
    
    
    <li>
         <label for="city">City</label>
        <input type="text" name="city" id="city" />
        <label for="state">State</label>
        <input type="text" name="state" id="state" />
    </li>
    
    
    <li>
         <label for="phone">Phone</label>
        <input type="text" name="phone" id="phone" />
        <label for="email">Email</label>
        <input type="text" name="email" id="email" />
    </li>
    
    


</ul>


<p><input type="submit" name="submit" id="submit" value="Place order" /></p>




</form>
</div>

Why a table? It's quite simple to understand: in this form, data are organized in name/field pairs (name, title, price, etc.), so the most semantical way to mark up this is using a table. Of course not all data is contained within a table, so this is another issue to take into account. Here's our CSS styles:

/* General styles */

body, h2, form, fieldset, table, th, td, ul, p, legend {
 margin: 0;
 padding: 0;
 border: none;
 list-style: none;
 color: #333;
}


body {
 background: #fff;
 color: #333;
 font: 76% Arial, Helvetica, sans-serif;
}

h2 {
 font-size: 1.6em;
 font-weight: normal;
 color: #666;
}

/* Give input elements a consistent dimension */

input {
 font: 1em Arial, Helvetica, sans-serif;
}


/* Styling the main container */


#order {
 width: 700px;
 margin: 2em auto;
 padding: 8px 6px;
}

/* Styling the form element just for IE6/7 */

form {
 height: 100%;  /* http://www.satzansatz.de/cssd/onhavinglayout.html */
}

/* Styling the main title */

h2 {
 text-align: center;
 text-transform: uppercase;
}

/* Styling the table for order details */

form table {
 width: 100%;
 padding: 6px 0;
 border-spacing: 0;
 border-collapse: collapse;
 margin-bottom: 0.5em;
}

form table th {
 text-align: left;
 font-weight: normal;
}

form table td {
 padding-bottom: 3px;
}

form table td input {
 border: 1px solid #ccc;
 display: block;
 margin-right: 4px;
}

form table td #copy1,
form table td #copy2,
form table td #copy3,
form table td #copy4,
form table td #price1,
form table td #price2,
form table td #price3,
form table td #price4 {
 width: 50px;
}


form table td #code1,
form table td #code2,
form table td #code3,
form table td #code4 {
 width: 70px;
}

form table td #title1,
form table td #title2,
form table td #title3,
form table td #title4 {
 width: 505px;
}


/* Payment method: fieldset and its children */

fieldset legend {
 font-weight: bold;
 padding-bottom: 5px;
}

fieldset ul {
 width: 100%;
 height: 100%;
 overflow: hidden;
}

fieldset ul li {
 float: left;
 width: 172px;
 margin: 0;
}

fieldset ul li label {
 font-weight: bold;
 vertical-align: middle;
}

fieldset ul li input {
 vertical-align: middle;
}


fieldset div.footer {
 width: 100%;
 padding: 10px 0 20px 0;
 height: 100%;
 overflow: hidden;
}

fieldset div.footer div.left {
 float: left;
 width: 200px;
 margin: 0;
}

fieldset div.footer div.right {
 float: right;
 width: 200px;
 margin: 0;
 position: relative;
 left: 17px;
}

fieldset div.footer input {
 vertical-align: middle;
 border: none;
 border-bottom: 1px solid #ccc;
}
fieldset div.footer label {
 vertical-align: middle;
 font-weight: bold;
}


/* Customer info */


form ul.customer-info {
 width: 100%;
 padding: 15px 0;
 overflow: hidden;
 height: 100%;
}

form ul.customer-info li {
 float: left;
 width: 340px;
 margin: 0 4px 0 0;
}

form ul.customer-info input {
 vertical-align: middle;
 border: none;
 border-bottom: 1px solid #ccc;
 width: 110px;
 margin-right: 5px;
}

form ul.customer-info label {
 font-weight: bold;
 vertical-align: middle;
 padding-right: 4px;
}


/* Submit button */

form #submit {
 border-color: #ccc;
 background: #666;
 font-weight: bold;
 color: #fff;
}

The rendering of the fieldset element is inconsistent in Internet Explorer 7 and lower, so we have to fix it using conditional comments:

<!--[if lt IE 8]>
<style type="text/css" media="screen">
fieldset legend {
 position: relative;
 left: -6px;
}
</style>
<![endif]-->

View the live demo

The secret here for achieving a good consistency across browsers is to explicitly specify a font size and family on form elements. By doing so, we can actually have proportional form elements that scale gracefully along text.

Leave a Reply

Note: Only a member of this blog may post a comment.