Yet Another Divs vs Tables issue: Forms

[Meta-note:] I was browsing the question page, getting really tired of "DIVS vs Tables" "When to use tables vs DIVS" "Are Divs better than Tables" "Tables versus CSS" and all the questions that ask THE SAME THING OMG PEOPLE but I would like to see all the ways people tackle the translation of the canonical example of "why you should give up and use tables":

<table>
  <tr>
    <td> Name </td>
    <td> <input> </td>
  </tr>
  <tr>
    <td> Social Security Number </td>
    <td> <input> </td>
  </tr>
</table>

Question: How to best (semantically, simply, robustly, fluidly, portably) implement the above without tables. For starters, I guess a naive implementation uses a fixed column width for the first column, but that can have iffy results for dynamically generated content. Including strengths/weaknesses of your approach in the answer would be nice.

P.S. Another one I wonder about a lot is vertical centering but the hack for that is covered pretty well at jakpsatweb.cz

EDIT: scunlife brings up a good example of why I didn't think out the problem that carefully. Tables can align multiple columns simultaneously. The Question still stands (I'd like to see different CSS techniques used for alignment/layout) - although solutions that can handle his? more involved example definitely are preferred.


Solution 1:

What I usually do is :

<form>
 <label for="param_1">Param 1</label>
 <input id="param_1" name="param_1"><br />
 <label for="param_2">Param 2</label>
 <input id="param_2" name="param_2"><br />
</form>

and in a CSS :

label,input { display: block; float: left; margin-bottom: 1ex; }
input { width: 20em; }
label { text-align: right; width: 15em; padding-right: 2em; }
br { clear: left; }

Of course, you'll have to define the width according to your actual data :-)

  • First, give label and input display: block, so that it can be assigned a size and be lined up.
  • They both get float: left because Explorer does things a bit differently
  • Format the label nicely
  • hack the br so that there's a clear: left somewhere, and I remember that putting it on the label didn't work on some browser.

Plus, with the br you get a nice formatting even if the browser does not support CSS :-)

Solution 2:

The trick is when the form gets more complicated than your sample, you realize that tables enable a "flexible grid" that no other elements do.

e.g. what if the "input" is more complicated than a text box? e.g. a bunch of radio buttons, each with their own label:

Color: [____Red___][v]
 Hood: [*] 
 Size: (_) Small
       (_) Medium
       (_) Large
       (*) X-Large

If all you need are simple forms, CSS is great, but as soon as you need a grid, things get interesting...

If you really want to do this, I would check out The Man In Blue's Solution, it works pretty well and is very clean.

Solution 3:

People talk about tables getting their forms to display the way they want, that's true, ONLY if you want to display your forms in columns and are willing to lose semantic meaning. With the following HTML in place, it's possible to display this form in as many layouts as you might wish.

BTW - No to the <br />

<form>
 <fieldset>
  <legend>Personal Info</fieldset>
  <div>
   <label for="name">Name</label>
   <input id="name" name="name" />
  </div>
  <div>
   <label for="ssn">Social Security Number</label>
   <input id="ssn" name="ssn" />
  </div>
 </fieldset>
</form>

You can clear the <divs> or set them to overflow: hidden to ensure that the floats are cleared.

Options from the above html:

Name |==============|    SSN |==============|

Name |==============|
SSN |==============|

Name     |==============|
SSN      |==============|

    Name |==============|
     SSN |==============|

   Name: |==============|
    SSN: |==============|

Name:
|==============|
SSN:
|==============|

All of the above can be accomplished with just a few lines of css.

When it comes to radio, checkboxes, and submit buttons it gets a little more complicated, but clean semantic HTML CAN be displayed the way you want it using css.