CSS Distress

I’m a big fan of CSS, and CSS positioning. I’ve always heard and believed the mantra “Use CSS for positioning; use tables only for tabular data”. It seemed wise to my young and innocent ears. However, I’ve recently been having some doubts, brought on by considering a common layout case.

Here’s my scenario. I want to have a series of labelled widgets, e.g. for a “Preferences” page. Quick ASCII art diagram:

Foo:          [ Freeform Text   ]
Bar Setting:  [ Sometimes Bar |V]
Baz?          ( ) Yes, Baz
(.) No, don't Baz
Quux:         [X]

(No, you don’t need to point out the number of UI design principles broken in this diagram. It’s an example.)

Doing this with CSS would involve something like two divs, one for the left side and one for the right, either floated or absolutely positioned, and a lot of messing about with vertical margins and padding trying to get the widgets to line up exactly with their descriptions at various font sizes. And, even if I managed it, is it the right thing to do? Would a screen reader read all the descriptions and then all the widgets?

Should I (whisper it) be using tables for this, even though it’s not really tabular data? Or is it?

35 thoughts on “CSS Distress

  1. The ‘right answer’ is to use display:table et al for the presentation layer, but not to use <table> for the semantics.

    Malcolm

  2. Of course, I should also mention that no browser actually supports that properly, so the practical way to achieve the effect you’re looking for is probably display:block, float:left, and an explicit clear at the end of each row (or at the start of the next row, perhaps).

  3. <form>
    <div class="formRow">
    <label>Foo:</label><textarea></textarea>
    </div>
    </form>
    

    This sort of thing gives you a lot of power. Turn the label display:block and float it left, give it a width and you’ve got a left hand “column”. Style the formRow class and you get separation between each label/formElement set.

    For more flexibility, use multiple classes on the div (class=”formRow address”) to style the label/formElement sets individually.

  4. As the others have mentioned, look at the method described on quirksmode.

    Give a width to [label] tags, and float them; ditto for [input]s (which implies display:block;). I’ve used a version of this method for an intranet app; the CSS for a [label] looks like this:

    float: left;
    clear: both;
    width: 7em;
    text-align: right;
    margin: 0.3em 1em 0 0;
    padding: 1px 2px 1px 0;
    background: #eed;
    color: #000;

    If you want to get clever, you can style [fieldset]s and [legend]s as well (margin, border, padding, clear). This lets your logical groupings be your presentational groupings as well.

    I also had a fieldset.halfwidth class (heresy! presentation leaking into HTML attributes!) which let me float two smaller [fieldset]s in a [form] side-by-side, using:

    float:left;
    clear:none;
    width:47%;

    The big win is that small-screen users don’t have the forms scrolling off horizontally as much (first, the [input]s wrap underneath the [label]s)

  5. In my opinion, the kind of fill-in form you use is a transposed table, rows are shown as columns and columns are shown as rows, with only 1 item to show in your data collection; think of headers as labels.
    If you would have multiple ‘preferences’ (or customers, or invoices, or whatever) rows to edit, you would also show them in a (regular) table.
    With this approach, you can use both table and CSS powers.
    Tables give you proper alignment, CSS give you layout flexibility:

    <table class=”form”>
    <tr>
    <th>Foo</th>
    <td><input type=”text” name=”foo” id=”foo” /></td>
    </tr>

    <tr>
    <td></td>
    <td><input type=”submit” text=”submit” /></td>
    </tr>
    </table>

    and something like this in your stylesheet:
    table.form {
    width: 500px;
    }
    table.form th {
    background-color: #999999;
    text-align: right;
    width: 30%;
    }
    table.form td {
    background-color: #99cc99;
    }

    I’ve strugled with div, span, float, clear, label, etc before, but no solution gave me the result (both in layout as in semantics) that I was looking for. This comes pretty close to what’s the perfect solution *for me*

  6. This is tabular data Gerv… If you really want to try a CSS-based thing, go and do it, but, and that’s with my old CSS WG member hat on, I’m telling you: use a table.

  7. There is no need to use divs, or to float the form elements (as in the quirksmode example).

    Using the same html as quirksmode (this is the most semanically correct IMO) the following style rule takes care of everyting:

    label {
    display: block;
    width: 6em;
    float: left;
    text-align: right;
    margin-right: 1em;
    }

    This requires that you prepend all radio buttons except the first with an empty label. It might be a good idea to use double br:s except between the radio buttons to get a better look.

    If the heiht of the label is significantly higher than the input elements, set the clear property on the br (it might be a good idea to do anyway, just in case).

    Set the line-height property on the form element to increase spacing between the form rows.

  8. What a great blog post! Thanks Gerv.

    I’ve been trying to find the best way of doing this for ages, and its been really interesting to see all these peoples different solutions.

    Nice, I’ve enough ammo to now to take on this problem (Hopefully you do to!) :)

    Mac.

  9. For what it’s worth, it looks like tabular data to me. Some of these answers, however, look like they might belong in the “CSS Tips” section over at Devmo. ;)

  10. Use table. It’s more generic and browser safe. You don’t need to decide the first column width and easy to control alignment. If you have this kind of preference form in many places, set style to table.

    For example :
    <style>
    .myTable {background-color:lightgrey;}
    </style>

    <table class=”myTable”>…..</table>

    It’s better to put generic style into css file. Then you can control layout easily.
    That’s beauty of style sheet.

    If you worry about accessibility, you can add
    <LABEL for=”Freeform_Text_field”>Foo</LABEL>

  11. I do not agree that labels and controls are tabular. If you do decide to use a table you don’t need a class. You could use “form table” as a CSS selector, which keeps you html cleaner. My defenition list also doesn’t have a class:

    form dt {
    position: absolute;
    z-index: 2;
    }

    form dd {
    position: relative;
    padding-left: 100px;
    }

  12. Quirckmode’s way is very nice (and correct) but you get into trouble when stuff gets more complex.
    To quote from Gervase’s sample, “Yes, Baz” also needs to be inside a label (to properly enable it’s “for” property). And what if you need an input type=text after that label, properly aligned and “Mph” behind that.
    Aligning all elements for all situations cross-browser can become quite daunting.

    Also, <legend> is only partly stylable, it would be nice if at least firefox would fix that.

  13. That’s definitely tabular data. Imagining column headings named “Option Name” and “Option Value” makes it quite obvious that you’re intentionally putting data in rows and columns. Using a table is the structurally correct thing to do in this case.

  14. Alper and Beat Bolli,

    did you guys ever print out your pages in Firefox? Look no good to me.

  15. I’ve written a very similar page recently for an intranet app. After some internal debate I decided that tables were the cleaner solution – I hadn’t thought of it in the same way as Joel Bruick but it’s a good point. Sites that dramatically overuse tables for layout would be able to name the columns.

  16. Hi!

    The suggestion I like the most so far is the dd/dt solution. Tables always generate more clutter (tbody, tr). I’d like to make a suggestion too.

    Go for the labels, because they are driving the layout. Labels can be “clear:both” and “float:left”, which ensures that “no two labels are on the same line”. This is already powerful, especially when textareas are involved. Fields benefit from being static (i.e. not floating).

    I like to give a padding-left to the container div instead of setting margin-left for the inputs, because it makes it easier to get a layout that fits upon window resize.

    Finally, a little markup for nested fieldsets with different alignments is worth a lot, but you should rarely need it, if ever. I’d rather redesign the form. If you do need, say, a date input with three labeled fields, I believe you would like to define a div (or something else) for calendar entries (if you give nice error messages with highlighted failed inputs, you’ll like it later). Besides, since the fields are actually one “input”, you can easily convince yourself that it isn’t really markup for presentation. : )

  17. I just use CSS. The proper container for a group of form elements isn’t a table, it’s a fieldset. If you then want to nest a table inside that then go for it, but the markup payload increases massively, and you start heading back to the bad old days. I don’t like the dl idea either – you’re not defining a term and a definition initally, you’re asking for input. My general CSS looks something like:

    label {
    display: block;
    width: 30%;
    float: left;
    clear: left;
    }
  18. I remember reading something a month or so back on some blog about styling forms elemts with css. I can’t find it again now but this may give you some ideas.

  19. In XUL you would use GRID. GRID in HTML is a table. As Daniel stated: use a table

  20. CSS-Only Forms has been hanging around del.icio.us/popular for the last few days. It seems like a fairly comprehensive look at the issue.

    (Although I do tend to agree with those who say that it’s tabular data.)

  21. Using a table is much more intuitive, browser safe and (if only one table level is used) still good human readable to me. I see no “killer argument” pro css. Well, beisde all those fuzzy “abstraction of content and design” or “screen reader compatibility” arguments that mostly don’t count a bit in real world…

  22. I just reread Malcom’s fist comment:
    “the ‘right answer’ is to use display:table et al…”

    But this would imply that you need something like this
    bla…

    Is that assumption correct? It doesn’t look very intutive for me.

  23. I’ve been using tables for this kind of thing for years. I tried to do it with CSS just once and I wanted to kill myself afterwards. There’s nothing wrong with putting form data in tables.

  24. Sure, but labels and inputs aren’t data. I deal with data tables all day in my job and I’m happy to use them for such, but it just doesn’t make semantic sense in this case. Whether or not you want to go with the defined semantics for html elements is a choice you’d want to make yourself, but seeing as it’s easy to lay forms out with CSS I know what I’m going to carry on doing.

  25. At the risk of repeating what others have said, and disagreeing with what even more people have said, I’d be inclined to say that you’re looking at tabular data here. Tables can be used for related datasets. For example, it would make perfect sense to use a table for a list of cities and their corresponding populations. Why not, therefore, use a table for a set of questions and their corresponding answers.

  26. FWIW, metooing to it being tabular data. I use tables for lining up labels and fields in cases like that.

    It seems to me the “all tables are evil” propaganda has succeeded too well.