Languages

Web Style Sheets CSS tips & tricks

See also the index of all tips.

Folding table columns

The two tables below can be shown in full or with one or more columns omitted. This page demonstrates two methods to switch between the different views. Either

First example table
Item Info Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
First 1st 56 28 85 24 67 27 67 20 21 74 45 48
Second 2nd 34 28 84 74 95 77 21 31 54 34 84 47
Second example table
Item Info Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
First 1st imo boo ba fie ro ore yu ek quo phe lei ats
Second 2nd eu eo suh ohn hye lef wa bu orf ir soi se

The 'visibility' property

Usually, to hide an element from view, you use the 'display' property and set it to 'none'. But CSS also has a property called 'visibility', which hides elements in a different way. In particular, we use 'visibility: collapse' here, which is designed especially for hiding table columns and rows.

With this method, the layout of the table is actually computed with the collapsed column still present, but that column is then not displayed. The effect is to leave unused space at the right edge of the table.

The 'collapse' value is meant for interactive use: at first all columns are visible, then something (we'll see below what) changes the value of 'visibility' on some columns from 'visible' to 'collapse'. Those columns disappear, but the contents of the remaining columns is not changed in any way. The columns only move closer together. When the value changes back to 'visible', the collapsed columns reappear and the other columns move back, again without changing the layout of any cells. That not only makes the process quick, it also helps your eyes to recognize each column after it moved.

To put style rules on table columns, there have to be elements in the document that represent those columns. In HTML, those are the <col> elements. The HTML code for the tables above looks like this:

<table>
<col>
<col>
<col class=m01>
<col class=m02>
<col class=m03>
<col class=m04>
<col class=m05>
<col class=m06>
<col class=m07>
<col class=m08>
<col class=m09>
<col class=m10>
<col class=m11>
<col class=m12>
<thead>
<tr>
<th>...

The class attributes are there to make it easier to write the style rules. One of those style rules is:

col.m04 { visibility: collapse }

This folds away any columns with class m04. Next we need a way to toggle this rule on and off.

Alternative style sheets

The first method involves alternative style sheets (see the article “Alternative style sheets”). This page has no less than eleven alternative styles called “View for…”, corresponding to eleven different ways to display the tables. The HTML code looks like this:

<link
  rel="alternate stylesheet"
  href="foldingstyle/month02.css"
  title="View for February">
<link
  rel="alternate stylesheet"
  href="foldingstyle/month03.css"
  title="View for March">
<link
  rel="alternate stylesheet"
  href="foldingstyle/month04.css"
  title="View for April">
...

Each of those alternative styles is only two lines: a line to import the default style sheet, and a line to collapse the relevant columns. E.g., here is the complete month04.css file. It hides the .m01, .m02 and .m03 columns, i.e., the columns for January, February and March:

@import "../../CSS/w3c-2010/main.css";
.m01, .m02, .m03 { visibility: collapse }

Alternative style sheets are an easy method. As you see, the style rules are short and simple. On the other hand, switching between styles is typically not very quick, because the user has to select a style from a menu. That involves a number of mouse movements or several key presses.

The ':target' selector hack

The second method relies on the ':target' selector. It selects the (at most one) element in a document that is the target of the link that you followed to reach that document. (See the article “A tabbed interface” for more about ':target'.)

We can use that selector here to style the table differently based on which element is the current target. Then we only have to provide links to those targets and with every click on a link, a different element becomes the target and a different style applies.

We need as many potential targets in the document as we have different styles, and hyperlinks to those targets. This page uses empty <div> elements as targets and puts the <a> elements inside the column headers:

<div class=hack id=view02></div>
<div class=hack id=view03></div>
<div class=hack id=view04></div>
...
<table>
...
<th><a
 title="Click to hide earlier columns"
 href="#view02">Feb<a>
<th><a
 title="Click to hide earlier columns"
 href="#view03">Mar<a>
<th><a
 title="Click to hide earlier columns"
 href="#view04">Apr<a>
...

(The title attributes explain a bit what happens for each link.)

These extra <div> and <a> elements have no other function than to support the style and that is why I call this method a hack. In some future extension of CSS there will probably be a way to toggle the style of elements directly (see below).

The style rules are a bit complicated. Here is one of them:

#view02:target ~ * .m01 {
  visibility: collapse }

It says to collapse the element .m01 if it is a descendant of an element that is itself a following sibling of the element that has the ID “view02” and is the current target. See the “view.css” style sheet for the full set of rules. (There are 66 of them for this particular example.)

These rules allow the reader to show and hide columns by clicking on column headers. An extra advantage is that each different way to display the tables has its own URL. E.g., http://www.w3.org/Style/Examples/folding#view06 opens the page with the columns Jan, Feb, Mar, Apr and May already hidden.

Normally, when you follow a link, the browser scrolls the window such that the target element is displayed near the top. In this case the targets are hidden from view:

.hack { display: none }

No specification defines what the browser should scroll to in that case, but hopefully it simply doesn't scroll at all.

Conflicting methods

As this page uses two different methods to fold columns, one of the two must take precedence. In this case, the alternative styles win: if you selected the “View for June” style and then click on the August column, the June column will not collapse.

It is easy, however, to reverse the precedence. The link to the style sheet with the ':target' rules looks like this:

<link
  rel=stylesheet
  href="foldingstyle/view.css"
  title="Main">

which means the style sheet is only loaded together with other styles called “Main” and not with any of the styles called “View for…” Just removing the title attribute is enough to make the style sheet apply no matter what alternative style is loaded.

Limitations and a possible future

This page shows two tables whose columns fold and unfold the same way and that is to illustrate the limitations of the two methods: It would in fact be impossible to collapse columns in the two tables independently.

As said above, the method with the ':target' selector requires the addition of extra elements in the source. Also, if you want to use hyperlinks for other purposes, e.g., for a table of contents, then you cannot use them for folding tables anymore. (On the other hand, you could build a similar trick with the ':checked' selector instead of the ':target' selector. That frees up the hyperlinks, but has other constraints. Another page shows an example with ':checked'.)

For these reasons, CSS should eventually get a feature to toggle directly between two or more styles for an element, without needing explicit hyperlinks.

As of July 2011, the CSS working group has not yet published a Working Draft with such a feature, but there are ideas. One such idea is to introduce a pseudo-class ':alternative'. A rule such as

ul:alternative { content: "+" }

would mean that <ul> elements can be toggled between two states and when the user toggles the element to the second, alternative state, a “+” is displayed instead of the contents of the element.

Bert Bos, style activity lead
Copyright © 1994–2021 W3C® Privacy policy

Created 7 July 2011;
Last updated Wed 06 Jan 2021 05:40:49 AM UTC

Languages

About the translations