Christoph Schiessl
Christoph Schiessl

Reputation: 6868

Best way to implement tab stops in valid XHTML?

For explanation imagine a simple address. Written in a HTML paragraph with line breaks it would like this:

Street: Example Street 1
City: Vienna
Zip Code: 1010
Country: Austria

Most of the time that's completely okay, but sometimes I have to achieve the following output:

Street:   Example Street 1
City:     Vienna
Zip Code: 1010
Country:  Austria

My thoughts so far:

  1. Should be valid XHTML and work or degrade gracefully in all major browsers
  2. Using tags in a semantically correct way is strongly preferred
  3. Because of point two: I hope there's a better solution than tables
  4. The problem is not limited to addresses - would be useful in other situation too

How do you achieve this output (using HTML and/or CSS)?

Upvotes: 9

Views: 7270

Answers (7)

panzi
panzi

Reputation: 7702

Or you can throw away all sanity (and semantics) and recreate tables using CSS (tested in Firefox and Chrome):

<html>
<head>
<title>abusing divs</title>
<style type="text/css">
div.details {
    display: table;
}
div.details > div {
    display: table-row;
}
div.details > div > div {
    display: table-cell;
    padding-left: 0.25em;
    padding-right: 0.25em;
}
</style>
</head>
<body>
<div class="details">
    <div>
        <div>Street</div>
        <div>123 Main Street</div>
    </div>
    <div>
        <div>City</div>
        <div>Vienna</div>
    </div>
    <div>
        <div>This is a very very loooong label</div>
        <div>...</div>
    </div>
</div>
</body>
</html>

Just kidding.

Upvotes: -2

SpoonMeiser
SpoonMeiser

Reputation: 20417

As others have mentioned, floated elements are the way to go here.

This would be my solution:

<p class="details">
    <span class="label">Street:</span>
    Some Street or other.
    <br />

    <span class="label">City:</span>
    A City.
    <br />
</p>

With CSS that looks like this:

p.details {
    padding-left: 200px;
}

p.details span.label {
    float: left;
    clear: left;
    width: 200px;
    margin-left: -200px;
}

Because the main text isn't floating, this avoid any issues where that text is long and needs to wrap; it stops the floating element becoming to wide and then floating below the label. This means that no special cases are needed for when this text is multi-line either, say, if you wanted to have a multi-line address.

Similarly, this method also works if the label data needs to wrap over multiple lines, since the next label clears the previous float.

Having the line breaks in there means it also degrades nicely and looks like you would expect when not using CSS.

This method works very well for laying out forms, where <label> elements are used instead of the spans, and the paragraphs can be selected in the CSS as any paragraph that is the child of a <form>.

Upvotes: 0

Kornel
Kornel

Reputation: 100110

I think you've taken "tables are bad" concept to the extreme.

  • Tables used purely for layout (when other element would be more semantic) are bad.
  • Tables for tabular data are good. They were intended for that purpose!

What you've got fits very nicely into concept of rows and columns, with headers (<th>) and data (<td>) – based on semantics, not only layout.

If you want to make it more explicit that it's an address, then use adr Microformat or add a <caption>.

Wrong approaches:

  • <dl>: "1010" is not a definition of "Zip Code". The other way round it makes a bit more sense, but the relationship is just as clear with <th><td>, it doesn't rely on CSS, and will look perfect regearless of user's font size.
    If you use <th> will be perfectly rendered even in lynx! Address in <dl> without CSS trick will look weird.
  • HTML's <address> element may not be appropriate for this, because it is intended only for page author's/maintainer's contact information. It also allows inline content only, so you would lose structure of the address.

Upvotes: 17

Eevee
Eevee

Reputation: 48546

I find that definition lists make much more sense than tables here. Float the dt to the left with a specific width and have it clear on the left. If either the label or the data are going to wrap, you'll have to do some post-element-float-clearing trickery to make this work, but it doesn't sound like you'll need that. (I think it's worth it, anyway; plus, do it once and you'll never have to do it again.)

You can even use :after to add the colons automatically, if you don't mind brushing off IE6.

Upvotes: 9

nickf
nickf

Reputation: 546055

Don't listen to the people saying that this is tabular data. Just because something has been presented in rows, it doesn't make it a table!

This is a great situation to use the dl, dt and dd tags. It's a bit of a stretch from what they're originally intended for, but it's still much more meaningful than a table, spans or divs.

<dl>
    <dt>Street</dt>
    <dd>Example Street 1</dd>
    <dt>City</dt>
    <dd>Vienna</dd>
    <dt>Zip Code</dt>
    <dd>1010</dd>
    <dt>Country</dt>
    <dd>Austria</dd>
</dl>

And the CSS:

dt {
    width: 150px;
    float: left;
    clear: left
}
dd {
    float: left;
}

That's fairly basic CSS - it probably won't hold up to a lot of situations (eg: two dd's in a row, a really long dt), but it's a start. Look at the inline-block property for the dt, and perhaps instead of using floating, you could set a left-margin of 150px on the dd.

Upvotes: 4

Herb Caudill
Herb Caudill

Reputation: 49952

No need for tables (not that tables would be really inappropriate in this setting). I do this kind of thing all the time.

<div class=DetailsRow>
  <div class=DetailsLabel>Street</div>
  <div class=DetailsContent>123 Main Street</div>
</div>
<div class=DetailsRow>
  <div class=DetailsLabel>City</div>
  <div class=DetailsContent>Vienna</div>
</div>
  ...etc

and

div.DetailsRow
{
clear:both;
}

div.DetailsLabel
{
float:left;
width:100px;
color:gray;
}

div.DetailsContent
{
float:left;
width:400px;
}

Upvotes: -1

Henrik Paul
Henrik Paul

Reputation: 67703

Tables are the way to go.

Upvotes: 2

Related Questions