CSS2 says that the visibility
property can take one of three values: visible
, hidden
, and collapse
. There are many examples of the first two, but I don’t see visibility: collapse
very often. Not surprisingly, support for it is spotty and not consistent across the various browsers.
This post compares visibility: hidden
, visibility: collapse
, and display: none
as interpreted by Firefox 3.6 (representative of Gecko-based browsers), Safari 4.0 (representative of Webkit-based browsers), Opera 10.10, and Internet Explorer 8.0 (with Compatibility View disabled). Update 3/23/2011: The newest versions of Firefox (4.0), Safari (5.0), and Opera (11.0) exhibit no change in behavior.
The collapse
value only applies to the table elements of row, row group, column, and column group. If applied to any other element, it is supposed to act as hidden
.
CSS3 uses the same definition for the visibility
property as CSS2, but the Table Module has not yet been finalized. The working draft does not reference visibility: collapse
at this time.
The collapse
property is described under CSS2’s Dynamic row and column effects section of the Tables section:
The ‘visibility’ property takes the value ‘collapse’ for row, row group, column, and column group elements. This value causes the entire row or column to be removed from the display, and the space normally taken up by the row or column to be made available for other content. Contents of spanned rows and columns that intersect the collapsed column or row are clipped. The suppression of the row or column, however, does not otherwise affect the layout of the table. This allows dynamic effects to remove table rows or columns without forcing a re-layout of the table in order to account for the potential change in column constraints.
In all of these examples the selected item (row, row group, column, or column group) has its background set to be yellow to confirm which table cells should be affected. The table cells have a bit of internal padding, and border-spacing
is set to 0.25em
(which is ignored when the Collapse borders option is seleted). Cells each have a 1 pixel black border, while the table itself has a 2px grey border. The table border is wider to make sure it’s not overridden when the borders are set to collapse.
The links within the explanations will set the examples to the reflect a particular configuration.
visibility
and display
on rows
Let’s first see how rows and rowsets are affected.
row 1, col 1 (row group) | row 1, col 2 (row group) | row 1, col 3 (row group) |
row 2, col 1 (row group) | row 2, col 2 (row group) | row 2, col 3 (row group) |
row 3, col 1 | row 3, col 2 | row 3, col 3 |
Firefox
For the most part, Firefox acts as expected for all the cases. visibility: hidden
hides the content of the cells (and the cell’s border when borders are not collapsed) but still leaves space for the hidden cell. To demonstrate the difference between visibility: collapse
and display: none
, choose row group 1 and switch between the two. visibility: collapse
maintains the width of the table (as per the specification) while display: none
reduces the table’s width since the longer cells no longer need affect formatting.
If you select collapsed borders,
visibility: collapse
, and row 1, you can see the black border overlapping the table’s grey border. It also causes the second row to be a pixel shorter than if you switch to row 2 (which also causes the extra black border goes away). What appears to be happening is the cell borders are changed to the color of the table border and the width added, but the row 1 case has the border still black and positioned one pixel higher. A close-up of the previous example (at right) of row 1 you can better see the overlap and border widths. The right and bottom table borders are also three pixels wide; only the left border stays at two pixels.
When a row is hidden with collapsed borders, the cell borders are still drawn, even though you would think that they would not appear because the entire row is hidden (image at right). The CSS 2 spec says of the
visibility: hidden
:
The generated box is invisible (fully transparent, nothing is drawn), but still affects layout. Furthermore, descendants of the element will be visible if they have ‘visibility: visible’.
Safari
For Safari,
visibility: hidden
and display: none
act as expected. visibility: collapse
seems to act just like visibility: hidden
, leaving space for the non-visible row rather than collapsing the space. One thing to notice is when borders are not collapsed, the space between the second and third rows is twice as much as expected (image at right), probably because of the use of the row group. Adding another row group around the third row does not add more spacing, however.
Safari hides the table border when the outer cells are set to visibility: hidden
and borders collapsed. The border doesn’t disappear when borders are not set to collapse.
Unlike Firefox, Safari does not show intra-cell borders when a row is hidden, but it does also hide the table borders on the sides with collapsed borders.
Opera
Opera has some problems with dynamically changing the visibility
property. The scripts on this page will automatically toggle the border-collapse
property for Opera, working around the problem. This behavior is unfortunate, since visibility: collapse
was meant to help with showing and hiding rows and columns dynamically without causing the table’s layout to change.
Using visibility: hidden
with collapsed borders causes odd (yet predictable) behavior for table and cell borders. If you hide the first row, the table border around the row is also hidden, just as with Safari. However, hiding the second row causes the hiding of not only the table border segments attached to the row but also the bottom borders of the first row. Hiding the third row hides the table border around the row as well as the bottom borders of the second row (image at right).
Using visibility: collapse
acts like Firefox with visibility: hidden
, showing the cell borders while borders are collapsed, but hiding them when borders are not collapsed while leaving space for the hidden row.
Internet Explorer
The behavior of IE is pretty close to that of Firefox except for borders and cell spacing.
When borders are set to collapse, IE hides the top or bottom table border if it’s attached to a collapsed row. Selecting visibility: collapse
on the third row shows only the black border on the bottom of the second row’s cells rather than the table’s grey border. Selecting it on the first row also hides the black borders, just as Opera does (except it does vertically collapse the content).
When borders are set to not collapse, IE seems to assign cell spacing to the top of each cell as well as the bottom of the table. Setting
visibility: collapse
on the first row with Collapse borders unchecked shows no space between the table’s border and the cell borders (image at right).
visibility
and display
on columns
CSS specifically notes how the visibility
property applies to columns:
If the ‘visibility’ of a column is set to ‘collapse’, none of the cells in the column are rendered, and cells that span into other columns are clipped. In addition, the width of the table is diminished by the width the column would have taken up. See “Dynamic effects” below. Other values for ‘visibility’ have no effect.
row 1, col 1 | row 1, col 2 (col group) | row 1, col 3 (col group) |
row 2, col 1 | row 2, col 2 (col group) | row 2, col 3 (col group) |
row 3, col 1 | row 3, col 2 (col group) | row 3, col 3 (col group) tall cell |
Column support is inconsistent among the browsers, so it’s no surprise that support for visibility: collapse
with columns is also inconsistent.
Firefox
Firefox is able to set the background color on columns (shown with none selected), and it correctly does not change the table cells with visibility: hidden
. Likewise, display: none
has no effect on the table, which seems correct since CSS 2 specifies that the only properties which apply to columns are border, background, width, and visibility.
As it does with collapsing rows, the computed height of cells remains the same even after collapsing the column with the tallest cell in a row is collapsed.
Both display: none
and visibility: hidden
cause the background color to no longer be yellow.
Where Firefox seems to differ from the specifications is the actual columns do not collapse if borders are collapsed (image at right). Interestingly enough, the content shifts over as you would expect. When borders are not collapsed, Firefox does appear to match the specs.
As with the row example above, Firefox seems to make the table’s grey border wider on all sides except the left.
Safari
Safari does not seem to handle visibility: collapse
on columns. That’s probably because it treats that setting the same as visibility: hidden
, which is not supposed to do anything with columns.
Unlike Firefox, Safari will still show the background color with either visibility
setting, but will hide the background color for display: none
. It also seems to have problems dynamically changing away from display: none
; the background color does not reappear. Selecting another setting (either border collapse, property, or column) makes the color reappear. This example contains a workaround for this behavior of Safari.
There is no extra cell spacing due to the column group, unlike row groups. This is probably because column groups are a logical grouping, not part of the actual object hierarchy.
Opera
Opera’s behavior with columns is just like Safari, except Opera has problems changing the background color with more than just switching away from display: none
. The script which handles the example automatically toggles Collapse borders setting to correct for this.
Internet Explorer
As with collapsing rows, IE sometimes does not completely render the border when borders are set to collapse. If you set
visibility: collapse
on column 1, you’ll see no border on the left (image at right). If you then select column 3 or the column group, you’ll see a thin black border but not the thicker grey border.
All borders appear as expected when borders are not being collapsed.
If you try to change the active column while display: none
is selected, the browser will reload the page in Compatibility View, which changes how IE renders the various properties. This script contains workarounds so IE won’t go into Compatibility View.
Cells spanning rows and columns
Taking what we’ve seen with rows and columns, we can for the most part predict what will happen with cells which span columns and rows.
row 1, col 1 | row 1, cols 2, 3, 4 | ||
rows 2, 3, cols 1, 2 tall cell |
rows 2, 3, 4, col 3 tall cell |
row 2, col 4 | |
row 3, col 4 | |||
row 4, col 1 | row 4, col 2 | row 4, col 4 |
Firefox
This example shows Firefox having similar behavior as above with the table border’s width and only content shifting with collapsed columns.
Firefox seems to be inconsistent with how it handles cells spanning rows vs. spanning columns. If you select
visibility: collapse
on col 2, the cell which spans across the first two columns still appears but its content is laid out as if the cell’s width wasn’t changed (image at right). If col 3 is selected, the spanned cell in the first row is a bit shorter than it should be.
If you then collapse row 2, the left two cells disappear. Each of those cells spans more than one row. They reappear if you collapse row 3 or row 4.
Revisiting the CSS2 description:
Contents of spanned rows and columns that intersect the collapsed column or row are clipped.
It would seem that the behavior of cells which span multiple rows (still show but are smaller) better fits this definition, rather than having the cell disappear altogether.
The first cell on the second row spans both rows and columns, but disappears if you collapse either col 1 or row 2. This indicates that the semantics for collapsing columns (hiding if the leftmost column is collapsed) are used for such cells rather than rows (truncating instead of hiding).
Unlike with the other columns example above, Firefox does honor display: none
on columns in this example, even though the display
property is not supposed to apply to columns. Note the cells in the last row are out of order when hiding col 1 or col 2.
Firefox seems to be inconsistent with borders for row 2, collapsed borders, and rows set to
display: none
(incomplete border below top right cell, image at right) as well as row 3 (row 4 also shows 5 cells) and row 4 (missing segment from the bottom table border).
Safari
While it does not match the spec, Safari is fairly consistent with its behavior in the other two examples. As above, visibility: collapse
matches visibility: hidden
. For spanned cells, if a cell’s top left position is hidden or collapsed, the entire cell will disappear, such as with row 2 or col 1. One exception is if you hide col 2, where you would not expect the long cell on the first row to still be showing (let alone have a yellow background).
Another odd behavior is if you set row 3 to display: none
. You end up seeing five cells across, with row 4 col 1 appearing to the right of the cell which spans down to the position of row 4, col 2. In addition, the cell which spans into row 2 and 3, cols 1 and 2 appears at the beginning of row 4 (even though it should not appear in row 4). Since the first and second columns are slightly different in width, there is some misalignment, too. The cell layout is actually the same as Firefox with these settings, even though the border and cell alignment are different.
Safari shows the same out-of-order cells in the last row as Firefox does when using display: none
to hide col 1 and col 2. Of course, cells shouldn’t be hidden for columns in the first place, but Safari does do so in this example, even though it didn’t in the columns example.
The table border looks pretty strange when using display: none
with borders collapsed, but it mostly seems to track the behavior with the row and column examples.
Safari has problems with inconsistently showing borders when changing rows and columns with display: none
. This script implements a workaround.
Opera
Opera’s behavior remains consistent with the first two examples. It also uses the top left position of a spanned cell to determine if a cell should be hidden.
Like Safari, Opera will still show the yellow background on the spanned cell of the first row when col 2 is hidden or collapsed.
Opera also shows out-of-order cells with display: none
, such as when col 2 is set to not display, making row 4, col 4 appear to the left of the tall cell in column 3.
Internet Explorer
Like Firefox, IE honors visibility: hidden
and display: none
on columns in this example, even though it (correctly) does not do so in the column example which doesn’t have spanned cells. It will also hide cells which span columns when the cell’s leftmost column is collapsed, as well as hiding cells which span rows if the cell’s topmost row is collapsed.
IE seems to have problems sometimes with not displaying all of the spanned cells if you choose between various options. This script works around that problem by toggling display: none
on the entire table when changes are made.
Using display: none
on columns will cause IE to hide cells, just as it did in the example above. However, the browser does not go into Compatibility View on this particular example when switching columns..
Like Safari and Opera, either visibility
setting on col 2 will not affect the spanned cell on the first row, even to the point where the background will remain yellow.
Also like the other browsers, using display: none
on columns causes some of the cells to be rendered out of order. As an example, doing this with col 1 causes rows 2, 3 and 4, col 3 to appear to the left of row 4, col 2.
Conclusions
While Firefox seems to get closest to the spec, none of the browsers hit all of the apects of CSS2’s definition on how to use visibility: collapse
in these examples. While they’re more consistent with visibility: hidden
and display: none
on rows, borders are often not reliable.
While not covered in these examples, setting display: none
on the row each of the cells does seem to work consistently. If you try to set it on just the cells, borders are not correctly rendered; in the last example, disabling the cells on the first row will cause Safari, Opera, and IE to not show the top table border. Firefox won’t show any borders for the entire table if they’re collapsed (but will if they’re not collapsed).
If you do disable rows in this manner, be careful about cells which span rows and/or columns. Also, the table will be re-rendered, possibly causing rows and columns to be resized. That behavior negates the purpose of visibility: collapse
.
Hopefully browsers will have better support in the future for collapsing rows and columns. It’s a nice idea to not have cell widths change when rows are shown and hidden. Of course, if rows and/or columns are dynamically added via the DOM, you very well may need to resize anyway to fit the new content.
[…] But unlike display:none which modifies the table layout after removing the space, the layout remains the same in visibility:collapse. You can see how it works in more detail over here. […]
[…] But unlike display:none which modifies the table layout after removing the space, the layout remains the same in visibility:collapse. You can see how it works in more detail over here. […]
[…] But unlike display:none which modifies the table layout after removing the space, the layout remains the same in visibility:collapse. You can see how it works in more detail over here. […]