Multi-Column Lists – A Record Aside

One of many minor holy grails of XHTML and CSS is to supply a single, semantically logical ordered checklist that wraps into vertical columns.

Article Continues Beneath

The best state of affairs, for my part, could be a single XHTML checklist whose wrapping is managed totally by CSS. Additional, the wrapped checklist ought to tolerate textual content resizing (simply achieved by styling every part in ems).

CSS and the browsers that help it don’t but present us with “vertical wrap,” so now we have to enhance fundamental checklist markup with extra attributes and styling guidelines to attain the impact. I’ll take you there—or as shut as we are able to get utilizing right this moment’s browsers—however alongside the best way let’s take a look at quite a lot of methods to perform an analogous impact.

We’ll be taking pictures for one thing that appears a bit like this:

An ordered list styled in vertical columns

(Why, you’ve probably been pondering, is this text entitled “CSS Swag”?  In attempting to find a metaphor for the multi-column checklist styling proven within the above screenshot, I pictured a strip of material that hung down, drew again as much as its preliminary peak, then draped once more…  A fast google led me to this glorious time period, which I had beforehand related solely with an Australian tramp’s bundle of possessions, and to a terrific etymology that hyperlinks swagger to sway.)

I’ll warn you up entrance. If you wish to current an inventory in a number of columns, you’ll must compromise. You possibly can sacrifice W3C internet requirements and use deprecated markup, you may dwell with markup that’s lower than semantically logical, you may tolerate a combination of presentation with content material, you may say goodbye to browser compatibility, or you need to use markup that’s heavy with attributes and styling that’s heavy with guidelines. Each street exacts a toll.

Whereas every of those strategies is straightforward sufficient to arrange, the acid check comes whenever you add or take away checklist objects in the middle of web site upkeep. How simple to switch is your chosen technique? Ideally, we must always be capable of merely insert or delete checklist objects and watch the checklist rewrap itself.

The fact shouldn’t be so ideally suited. Not like the horizontal wrap that our browsers deal with robotically, vertical wrapping requires us to explicitly state which checklist objects happen by which columns or the place the columns ought to break. To maintain a modified checklist wrapping correctly, we should rearrange the checklist objects, change courses and attributes within the markup, or tweak guidelines within the stylesheet.  The one method described right here that doesn’t want any of that fuss (Technique 1) has different critical behavioral issues.  Lastly, as a result of vertical proportions are so vital right here, most of those lists are going to interrupt if we assume that every checklist merchandise will occupy one line, solely to have some objects wrap to 2 or extra traces.

So why can we trouble?  Effectively, as a result of the ultimate impact is so cool—and sensible.  Wrapping an inventory into columns can relieve the web site customer of the need to scroll down a protracted checklist.  A 3- or four-column checklist can fill the width of a web page whereas a single skinny column might go away the format wanting anemic.  There are as many causes to wrap lists as there are internet designers:  very undoubtedly Extra Than A Few.

To work, then.

First, expunge all white house#section3

The default rendering of an XHTML ordered checklist in browsers is that of a single vertical collection of things:


Default rendering of ordered lists

To bypass some browser inconsistencies, I’ve taken to marking up my lists like this:


I’ve moved the final closing angle-bracket > of every row to the start of the following row.  This retains every checklist merchandise on a row by itself for the advantage of human readers and on the similar time successfully eliminates the entire white house between tags, this producing extra constant rendering throughout browsers.

(My pet idea as to why Web Explorer contains the white house between list-item tags in its rendering calculations is that it’s a hold-over from that prehistoric period when checklist objects, like desk cells, didn’t have closing tags.  Again then, a browser correctly paid consideration to all textual content together with white-space from one start-tag <li> to the following.  When closing tags had been added to the combo, apparently nobody at Microsoft remembered—or deemed it vital sufficient—to regulate the logic to cease parsing between one closing tag </li> and the following start-tag <li>.)

Additionally, I’m including a hyperlink to every checklist merchandise.  This enables me to examine for abnormalities in rendering anchors when numerous CSS guidelines are utilized:

    ><li><a href="#">Aloe</a></li

Observe: most of my examples use ordered lists as a result of merchandise sequence is paramount on this train; unordered lists could, in fact, be substituted.

And yet another factor: the instance pages hooked up to this text are all marked up with a strict doctype. I exploit this in all my internet work lately as a result of it seems that I can get extra constant outcomes cross-browser with much less weeping and gnashing of enamel.  For those who use a transitional doctype or run in quirks mode, it’s possible you’ll have to tweak the CSS to get these strategies to behave cross-browser.

Technique 1: Floating checklist objects#section4

Of the entire strategies I’m going to explain, this one makes use of the cleanest XHTML markup and a few of the easiest CSS.  Sadly, its flaws forestall it from turning into my technique of alternative.

Method 1: Floating list items

See Instance 1.

The method is straightforward: give the checklist objects a set width and float them left.

The checklist objects wrap horizontally like phrases in a paragraph.  Typically talking, when a collection of blocks are floated left or proper, they align horizontally and wrap round after they attain the utmost width of their container.  If simply three objects can match on one row, as on this instance, the checklist naturally wraps into rows of three columns.

The XHTML markup is an easy checklist with no particular courses or different attributes required.  To forestall subsequent web page components from being affected by the float I’ve contained the checklist in a <div> and cleared the float with a (non-semantic) <br />:

<div class="wrapper">
    ><li><a href="#">Aloe</a></li
    ><li><a href="#">Bergamot</a></li
    ><li><a href="#">Oregano</a></li
    ><li><a href="#">Pennyroyal</a></li
  <br />
</div><!-- .wrapper -->

The important CSS is transient:

  /* enable room for 3 columns */
    width: 30em;
  }  /* float & enable room for the widest merchandise */
  ol li
    float: left;
    width: 10em;
  }  /* cease the float */
    clear: left;
  }  /* separate the checklist from subsequent markup */
    margin-bottom: 1em;

Easy methods to edit: objects may be added or eliminated with no additional modifications to the XHTML or CSS.

This technique suits two of our standards for a great resolution. The checklist itself is an easy, single XHTML checklist and the column-wrapping is managed totally from the stylesheet. Nonetheless, it falls in need of our objective as a result of the checklist sequence runs throughout after which down as an alternative of descending in vertical columns.  Additionally, it doesn’t survive effectively cross-browser: Web Explorer and Opera suppress the merchandise markers (ol numbers and ul bullets) when checklist objects are floated left or proper.

Technique 2: Numbering break up lists with HTML attributes#section5

This tactic—maybe born of a determined need to tame internet design to be as obedient as print design—is to separate the checklist into a number of sub-lists and prepare them aspect by aspect.

Method 2: Numbering split lists in XHTML

See Instance 2.

This method has a number of flaws: the semantic integrity of the only checklist is sacrificed; checklist wrap, which I contemplate presentational, is set totally by the HTML markup reasonably than by the stylesheet; and merchandise numbering resets to “1” with every new checklist.

That final hurdle, at the least, may be leapt over if you happen to don’t thoughts utilizing deprecated markup.  (To ensure that this markup to validate, you’ll want to make use of a transitional doctype.)

As Instance 2 demonstrates, the now-deprecated HTML attributes begin and worth allow us to reset checklist numbering.  If we ignore the W3C suggestion and use deprecated markup, we are able to mark up separate lists to provide the phantasm of 1 steady sequence.

Right here’s an instance I’ve pared down to focus on the attribute placement:

  ></ol>  <ol begin="3" 
  ></ol>  <ol
    ><li worth="5">merchandise</li

These checklist objects can be numbered sequentially 1–6 by browsers and different person brokers that also help the deprecated markup.

The stylesheet’s solely job, then, is to drift the sub-lists aspect by aspect, then clear the float after the ultimate column.  (In them olden days earlier than we bought faith, sub-lists had been generally positioned inside adjoining desk cells.)

Easy methods to edit: When checklist objects are added or deleted, some objects will should be moved from one sub-list to a different to take care of a constant column size.  If the variety of objects per column modifications, the begin and worth attribute values in XHTML will should be tweaked to take care of correct numbering.  No CSS modifications are required.

Technique 3: Numbering break up lists with CSS generated content material#section6

For those who’re splitting your checklist into chunks, one other device for numbering the objects contiguously is CSS content material technology, whereby a stylesheet causes textual content to look that doesn’t exist within the XHTML markup.

Method 3: Numbering split lists with CSS

See Instance 3.

Record merchandise numbering and bulleting are literally two cases of content-generation, however they’re the one ones which can be supported universally, most likely as a result of they date again to early HTML earlier than CSS was born.  The opposite types of CSS content-generation are ill-supported in right this moment’s browsers: of these examined, solely Opera rendered this instance correctly.

The XHTML markup is just like that in Technique 2 however even cleaner: the checklist is split into two or extra sub-lists, however the begin and worth attributes are omitted.

Utilizing CSS we suppress regular checklist merchandise numbering, then apply the pseudo-element :earlier than to insert incremental values:

  ol li
    list-style-type: none;
  }  ol li:earlier than
    content material: counter(merchandise) ". ";
    counter-increment: merchandise;

Sharp eyes could have caught one refined distinction in formatting within the screenshot above: the numbers generated with :earlier than are rendered flush-left, whereas browsers sometimes align ordered checklist numbering flush-right.  This impacts the alignment of the merchandise values when the variety of digits modifications, as in 9 to 10 above.

Easy methods to edit: When objects are added to or faraway from the general checklist, some objects will should be moved from one sub-list to a different in XHTML to take care of a constant column size.  No additional change is critical to both XHTML or CSS to protect correct numbering.

Sadly, this method is not going to be sensible for any cross-browser goal till extra browsers help the :earlier than pseudo-element.  For now, Opera’s the one browser that may render it.

Numbering break up lists with script#section7

Whereas we’re as regards to content-generation, I’ll add in passing that the objects in break up lists will also be “bodily” numbered contiguously by a script that inserts numbers into the merchandise values, both server-side throughout web page technology or client-side upon page-load.

A server-side script reminiscent of ASP or PHP, studying checklist merchandise values from a database or a flat file, can prepend a consecutive quantity to every merchandise because it’s written to the web page.  It could actually additionally divide the full variety of checklist objects by the specified variety of columns and generate the sub-list markup.  The duty of arranging the sub-lists aspect by aspect may be left to a static stylesheet.

A client-side script reminiscent of JavaScript can find the sub-lists utilizing ids or courses and iterate by way of the objects, inserting merchandise numbers, suppressing regular ordered checklist numbering, and splitting one lengthy checklist into sub-lists as wanted.

It ought to go with out saying (however doesn’t) that any resolution that makes use of client-side scripting ought to gracefully degrade in browsers with scripting turned off.

Wrapping a single checklist#section8

As we’ve seen, splitting an inventory into sub-lists and forcing consecutive merchandise numbering can produce the specified beauty impact, however these options aren’t as satisfying to me as one which preserves the integrity of the only checklist markup.

To wrap a single checklist into columns, I exploit CSS to seize every merchandise that begins a brand new column and drag it again as much as the extent of the primary merchandise after which over to a brand new left margin.  Regular rendering does the remainder.

Now we’re talkin’ swag!

Listed here are 3 ways to mark this up:

Technique 4: Wrapping a single checklist with XHTML#section9

For those who’re prepared to manage the place the column-wrap happens utilizing the XHTML markup, it’s simple sufficient to mark every merchandise in accordance with which column it belongs to.  A further class identify marks the primary merchandise of every column.

Method 4: Wrapping a single list with XHTML

See Instance 4.

Right here’s an abbreviated instance:

    ><li class="column1">merchandise</li
    ><li class="column1">merchandise</li    »
    ><li class="column2 reset">merchandise</li
    ><li class="column2">merchandise</li    »
    ><li class="column3 reset">merchandise</li
    ><li class="column3">merchandise</li

The stylesheet makes use of these courses to determine the horizontal column positions:

  li.column1 { margin-left: 0em; }
  li.column2 { margin-left: 10em; }
  li.column3 { margin-left: 20em; }

Then we mandate the line-height of every merchandise and produce the primary merchandise of every column again as much as the extent of the primary merchandise:

    line-height: 1.2em;
  }  li.reset
    margin-top: -6em;

Vertical return = variety of objects in a column ∗ peak of every merchandise.  On this case, 5 objects ∗ 1.2em = 6em.  (After I’ve tried making the line-height smaller than 1.2em I’ve run into cross-browser discrepancies.)

Easy methods to edit: When objects are added to or faraway from the checklist, the XHTML markup have to be tweaked to provide objects the right column-classes, and the reset class have to be moved to the primary merchandise of every column.  When the variety of objects per column modifications, the CSS li.reset{} rule have to be modified accordingly.

This isn’t my most popular method as a result of the column-wrapping is managed from the XHTML markup reasonably than the stylesheet.  The best way I take a look at it, wrapping an inventory into vertical columns is a matter of presentation, not content material, and subsequently should be managed by the stylesheet within the pursuits of separating content material from presentation.

Wrapping a single checklist with CSS#section10

In Strategies 5 and 6 that observe, the factors at which the checklist wraps to a brand new column are managed wholly from the stylesheet.

The value we pay is a few heavy XHTML markup, gravid with class names.  Verify this out:

We put together the markup by assigning a novel class to every checklist merchandise:

    ><li class="aloe">Aloe</a></li
    ><li class="berg">Bergamot</a></li
    ><li class="cale">Calendula</a></li
    ><li class="oreg">Oregano</a></li
    ><li class="penn">Pennyroyal</a></li

(I’m utilizing class as an alternative of id right here in order that I’ll have the liberty to incorporate multiple wrapped checklist on the identical web page; a category could apply to multiple object, however an id have to be distinctive.  The vital factor is that every merchandise is uniquely recognized inside its checklist.)

Within the stylesheet, we assign a distinct left margin to every group of things that belong in a single column:

    margin-left: 0em;
  }  li.feve,
    margin-left: 10em;
  }  li.kava,
    margin-left: 20em;

That is paying homage to the “columnN” courses in Technique 4, nevertheless right here the dedication of which merchandise belongs to which column is set purely on the CSS aspect of the road.

Oh, the irony of all of it!  The prospect of assigning a novel class to every checklist merchandise is sufficient to make eyes cross and toes curl.  In any case, the explanation we’re utilizing ordered lists within the first place is to make the most of the automated checklist numbering that our browsers present.  If now we have to call every checklist merchandise class uniquely, why not simply quantity the checklist objects themselves and be carried out with it?

Simple, now.  Breathe.  The task of distinctive merchandise courses isn’t about numbering the objects, it’s concerning the presentation of the entire checklist—discovering methods to steer the browser to wrap it into columns with out really having to cut the checklist into items and paste them aspect by aspect.  In internet design we assign courses and ids to web page components routinely to information CSS presentation; that’s what they’re there for.  Make no mistake, assigning a distinct class to each merchandise in an inventory is nobody’s concept of chic code, however it works, it validates, and it doesn’t (in my humble opinion) make the markup intrinsically ‘un-semantic.’

Whether or not it’s value your whereas to handle the code for any of those strategies whenever you modify an inventory will rely upon how a lot you need multiple-column lists to work.  Luckily, it’s not that huge a deal.  Modifying small lists by hand is straightforward, and if you happen to’ve bought a very lengthy checklist that’s continually altering you must most likely be producing it from a database within the first place.  One comfort is that once we’re producing pages from a server-side script we are able to assign distinctive checklist merchandise courses robotically so we don’t must get our fingers soiled.  (Or drained.)

Technique 5: Wrapping a single checklist utilizing absolute positioning#section11

As a result of we’ve now recognized every merchandise uniquely inside the checklist, one doable method is just to place every merchandise explicitly.

Method 5: Wrapping a single list using absolute positioning

See Instance 5.

Observe that this isn’t a sensible cross-browser resolution right this moment for ordered lists, since neither Web Explorer 6 nor Opera 7 will show checklist markers when checklist objects are styled {place: absolute;}.

To make this work for the remainder of the browsers, all the checklist have to be enclosed inside a div with {place: relative}: this offers the absolutely-positioned checklist objects a body of reference so we are able to forestall them from merely flying as much as the highest of the web page.  Then it’s merely a matter of assigning vertical positioning to each aspect.  We are able to do that in rows:

    place: absolute;
  }  li.aloe, li.feve, li.kava { prime: 0.0em; }
  li.berg, li.ging, li.lave { prime: 1.2em; }
  li.cale, li.hops, li.marj { prime: 2.4em; }
  li.dami, li.iris, li.nutm { prime: 3.6em; }
  li.elde, li.juni, li.oreg { prime: 4.8em; }
  li.penn                   { prime: 6.0em; }

Easy methods to edit:  When the variety of objects per column modifications, the stylesheet will should be modified.  When objects are added to or faraway from the checklist, the stylesheet have to be edited to re-determine which objects reside by which columns.  Each new checklist merchandise have to be assigned a novel class in XHTML.

Completely positioning each merchandise in an inventory is a control-freak’s dream, the kind of method many people took once we first got here to the online from print design and hadn’t but realized to let go.  To create multiple-column lists it isn’t essential to place each merchandise, as Technique 6 will reveal, however I’m together with it right here for the sake of completeness.  It does ’break’ otherwise from Technique 6 and that is perhaps one foundation for selecting it:

If any checklist merchandise is lengthy sufficient to wrap round to a second line, how does that have an effect on the format of the checklist?  When checklist objects are completely positioned as in Technique 5, the general format will stay unchanged, however the checklist merchandise that wraps can be overlaid by the following merchandise within the checklist which is able to declare its place with out regard to previous textual content, since absolute positioning takes every merchandise out of the circulate.  In distinction, in Technique 6 beneath every column of checklist objects descends by regular circulate; an inventory merchandise that wraps will push down subsequent objects, lengthening the column it’s in.  As a result of that technique assumes a set column peak, the vertical return will then be inadequate to carry the following column again as much as the highest, making a staggered format.

There could also be different ramifications of absolute positioning that can have an effect on our alternative: for instance, some browsers don’t allow the person to focus on textual content in absolutely-positioned blocks.

Technique 6: Wrapping a single checklist utilizing regular circulate#section12

Lastly, right here’s the method I choose to make use of: a single semantically-logical checklist whose column-wrapping is managed totally from CSS, depends on regular circulate, and works in most trendy browsers.

Method 6: Wrapping a single list using normal flow

See Instance 6.

As within the earlier technique, every checklist merchandise is given a novel class identify in XHTML, and the left margin of every column is stipulated in CSS.

What differentiates this technique is that right here we use these distinctive merchandise courses to carry the primary merchandise of every column again as much as the highest utilizing a unfavourable margin-top:

    line-height: 1.2em;
  }  li.feve,
    margin-top: -6em;

Once more, vertical return = variety of objects in a column ∗ peak of every merchandise.  On this case, 5 objects ∗ 1.2em line-height = 6em.

Easy methods to edit: when objects are added to or faraway from the checklist, the distinctiveness of merchandise class names have to be maintained in XHTML and the stylesheet have to be tweaked to shift objects to their correct columns.

With just a little additional styling and a few background photos, the checklist can get able to get together with out breaking the multi-column circulate.

Example 7: Gettin’ fancy

See Instance 7.

There are lots of methods to show a multiple-column checklist.  As we’ve seen, a lot of them require a compromise of internet requirements or browser-compatibility, in addition to some fairly furry markup and styling.  The only option, for my part, is to provide the XHTML markup ample “hooks” to permit the column-wrapping to be managed totally from CSS.

What we actually want is for some brilliant bulb to return alongside and determine how to do that with spare markup—and truly declare that holy grail.

Now, go forth and swag!

The examples for this text look considerably the identical (besides the place particularly famous within the textual content) in Home windows browsers Firefox 1.0, Web Explorer 6, Mozilla 1.7.2, Netscape 7.1 & 6.2, and Opera 7.23, and in Macintosh browsers Firefox 1.0, Web Explorer 5.2, and Safari 1.0.3.

Much less profitable with these strategies are Home windows Web Explorer 5.x and earlier, Linux Konqueror 3, and Netscape 4.x.  Maybe with coaxing they may very well be persuaded to return alongside as effectively.

Due to Angela Marie, B.J. Novitski, Bruno Fassino, Ingo Chao, Larry Israel, and Zoe M. Gillenwater for his or her useful criticism and browser peeks.

Angel Wing {photograph} in instance seven by Sophie Arés Pilon.

Leave a Comment