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:

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:

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:

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:

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.)

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.