Use CSS display:table for Layout

Posted on: Sunday, February 15th, 2009 at 11:34 pm

I had this post in draft since October 2008. I thought I’d redesign this blog site using display:table and explain that in a series of posts, starting with this one. But I never found the time for the redesign!

Still, I have been using display:table on a much larger site for about 6 months now, so I thought I might as well post this as it is, and perhaps follow up with more examples later.

Also, about 3 weeks after I started this draft, Rachel Andrew and Kevin Yank wrote a book on CSS display:table for layout, as well as a useful summary article! I do recommend looking at that article for finer details.

No need for css float for layout in modern browsers

For a few years now, web developers doing CSS-based layouts have used floats or absolute positioning for layout web sites to avoid using non-semantic HTML <table>s.

While doable, extra hoops often have to be jumped through (mostly for IE) and some seemingly simple things can be harder than necessary (like equal height columns).

However, for a simpler solution, CSS-based display:table, display:table-row, display:table-cell etc are all usable today across Firefox 2+, Safari 3+, Opera 9+ and IE8.

Example:

Consider the following HTML:

<body>
	<div id="header">
		<!-- header -->
	</div>

	<div id="content-body-wrapper">
		<div id="content-body">
			<div id="primary-nav">
				<!-- some navigation column here -->
			</div>
			<div id="secondary-nav">
				<!-- some additional column here -->
			</div>
			<div id="content">
				<!-- main content here -->
			</div>
		</div>
	</div>

	<div id="footer">
		<!-- footer -->
	</div>
</body>

And the CSS to style it to get equal height columns:

#content-body-wrapper {
    display:table;
    border-collapse:collapse;
}

#content-body {
    display:table-row;
}

#primary-nav, #secondary-nav, #content {
    display:table-cell;
}

#primary-nav, #secondary-nav {
    width:20%;
}

#content {
    width:60%;
}

And that’s it!

The above is just the layout bit of the CSS. Here are some screenshots (click for full size) with content and very basic styling just to see the equal height column effect:

The first is with Firefox 3 and the second with IE8.

You can actually omit extra divs, even the one that gets display:table and the browser is required to create an anonymous table for you.

Isn’t using table for layout wrong?

This is not the same as using the structural html table elements for layout purposes — that indeed is an inappropriate use for tables.

This is using CSS to give table-like display, which is fine as it leaves the HTML (and document structure) in tact.

What about IE 7 and 6?

IE7 and 6 of course remain problems, but you can use conditional comments and give them older techniques that attempt to achieve this.

Some limitations or issues

Some limitations of css display:table I have come across, however, include these:

  • Lack of colspan/rowspan equivalents
  • Like HTML tables, a CSS cell can expand in width based on content (as well as height).

On the last one I noticed this when using things like <pre> even with overflow:auto with the thought that just like inside floated columns with widths assigned this would result in those <pre> blocks getting horizontal scrolls if they became too wide.

Instead, as with HTML tables, they push out the cell they are in. The only workaround I knew to this was to give a px or em width to such elements. (It also applies to large images in a cell.)

That being said, display:table seems a lot cleaner!

CSS3 has an advanced layout module in the works but there are not any browser implementations of it (that I am aware of), so in the interim this could be a useful approach.

More info

Translations

Update: May 2010. Translated into Belorussian, by Ucallweconn

Share this

These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Facebook
  • TwitThis
  • Digg
  • del.icio.us
  • StumbleUpon
  • Ma.gnolia
  • NewsVine
  • Reddit
  • Slashdot
  • Technorati
  • YahooMyWeb

About this post

Post Navigation

15 Responses to “Use CSS display:table for Layout”

  1. On February 25th, 2009 at 5:32 pm AaronSieb said :

    I’ve been playing with this technique as well, but there’s something about it that bothers me…

    If you take the main portion of your markup, and convert the DIVs into appropriate tags, we end up with this structure:

    That’s the same number of tags, with the same number of CSS hooks. How is this any worse than the same set of DIVs? Especially when you consider that THIS structure is supported by the most popular browsers on the ‘net?

    I just wish there was a way to access the display: table-cell behavior, without needing to nest it inside of display: table and display: table-row… The extra markup overhead is enough to make me question CSS.

  2. On February 25th, 2009 at 5:34 pm AaronSieb said :

    Aaand, it ate my markup. Hopefully this shows up as somewhat readable.

    <table id=”content-body-wrapper”>
    <tr id=”content-body”>
    <td id=”primary-nav”>
    <!– some navigation column here –>
    </td>
    <td id=”secondary-nav”>
    <!– some additional column here –>
    </td>
    <td id=”content”>
    <!– main content here –>
    </td>
    </tr>
    </table>

  3. On April 2nd, 2009 at 10:48 am Sanjeev said :

    Hi,

    What is the exact fix for IE 6, I tried it in mozilla and i was really happy by seeing the output. Please can anyone provide the fix for IE

    Sanjeev

  4. On April 11th, 2009 at 5:21 am Sanjeev said :

    Thanks Anoop,

    Actually i was really trying very hard to find some table layout without using Table then, i come across some techniques…

    left block
    body block
    right block

    * {margin:0;padding:0;}
    #main{display:table-row; list-style-type:none }
    #left,#body,#right {display:table-cell;}

    Its really worked for me

  5. On April 11th, 2009 at 5:26 am Sanjeev said :

    Thanks Anoop,

    Actually i was really trying very hard to find some table layout without using Table then, i come across some techniques

    <ol id="main">
    <li id="main">left block</li>
    <li id="main">body block</li>
    <li id="main">right block</li>
    </ol>

    <style>
    * {margin:0;padding:0;}
    #main{display:table-row; list-style-type:none }
    #left,#body,#right {display:table-cell;}
    </style>
    Its really worked for me

  6. On January 26th, 2011 at 8:50 pm Stephen Akins said :

    You can use jQuery to make all of the cells on the same row, the same height… even if there are a dynamic number of cells on each row (meaning all of the rows “Float Left” but the number of DIVs on each row depend on the width of the user’s browser window).

    Here is the jQuery for those of you who are interested (I’m assuming the floating DIVs have the class “floatingDiv” assigned to it):

    $(document).ready(function() {

    var currentTallest = 0;
    var currentRowStart = 0;
    var rowDivs = new Array();

    $(‘div.floatingDiv’).each(function(index) {

    if(currentRowStart != $(this).position().top) {

    // we just came to a new row. Set all the heights on the completed row
    for(currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) rowDivs[currentDiv].height(currentTallest);

    // set the variables for the new row
    rowDivs.length = 0; // empty the array
    currentRowStart = $(this).position().top;
    currentTallest = $(this).height();
    rowDivs.push($(this));

    } else {

    // another div on the current row. Add it to the list and check if it's taller
    rowDivs.push($(this));
    currentTallest = (currentTallest < $(this).height()) ? ($(this).height()) : (currentTallest);

    }
    // do the last row
    for(currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) rowDivs[currentDiv].height(currentTallest);

    });

    });

  7. On February 18th, 2011 at 8:39 pm Bob Hurt said :

    depending on the fickle machinations of IE-land, you may need the following meta tag (or something similar) in your ‘head’ section:

    <meta http-equiv=”X-UA-Compatible” content=”IE=EmulateIE8″ />

    for an explanation of why Microsoft thinks this is desirable:
    http://msdn.microsoft.com/en-us/library/cc288325%28v=vs.85%29.aspx

  8. On May 16th, 2011 at 5:06 am AK said :

    CSS tables give the best of both worlds. But as usual IE is making front-end developers disappointed, IE6 amazingly has a big market share today and is mostly used in business environment.

  9. On May 29th, 2011 at 5:16 am steve said :

    I don’t see the meaning of these (yet a lot buggy) properties.

    Seeing that {display:table-cell} doesn’t need a specific parent, it seems not so different than {display:inline-block}.
    Not to mention that {display:table-column} doesn’t work at all …

    Much better and much more interesting the CSS3 {display:box} with the others following box-properties.

  10. On May 29th, 2011 at 11:41 pm Stephen Akins said :

    @AK – See my comment above for using jQuery to solve the issue. It works perfectly in any browser that supports jQuery, including many mobile browsers.

  11. On August 18th, 2011 at 2:42 pm When learning html - DesignersTalk said :

    [...] Use CSS display:table for Layout — onenaught.com Quite old but is it right? [...]

  12. On September 14th, 2011 at 4:44 pm MJ said :

    @Stephen Akins: using javascript to make columns’ height equal is only good if the content inslde those columns is not dynamic (for example slide down elements or loading content dynamically with AJAX depending on user action).

    Once the heights are set on DomReady you would need a lot more code to recalculate proper height everytime something changes dynamicallly. Even then you could get page flicker when recalculating proper height.

    And what about when the height of some content elements is animated?

  13. On September 14th, 2011 at 9:12 pm Stephen Akins said :

    @MJ

    That’s a good point, but I don’t think it’s difficult to fix. For instance, I have already modified my code above to work with the onresize event. (see http://stephenakins.blogspot.com/2011/01/uniform-div-heights-for-liquid-css-p.html). It’s not the same thing as what you’re talking abot but if the dynamic content could be made to trigger a reflow function that first got the new height, it should work fine. Maybe I’ll update my code to accommodate dynamic content.

Post a Comment