Flexible panel layouts revisited

A couple of years ago I wrote a small post about what I call "panel layouts" and how to create them with CSS. I've used the method succesfully for a number of projects since then but there was always something that bothered me: to make it work, browsers had to be forced to render in the content box model using a forced quirks mode. Recently I started using another way, that eliminated this problem.

Flexible panels

The ideal I'm trying to achieve is to have a viewport-filling layout with flexible and fixed panels combined. A common example is what I usually refer to as the "Outlook layout". Here's a more complex example.

The hard part here is to have flexible panels that fill whatever space isn't taken up by other (fixed) panels. Ideally you'd be able to write something like this:

.contentPanel {
    width: calc(100% - 200px);
    height: calc(100% - 400px);
}

...which in CSS3, you will be able to. However, we're not going to wait for that, so we're going to use an often-ignored feature of CSS: if you have an absolutely positioned element and you specify left and right but not width, the width becomes flexible: the edges stick to their coordinates. The same goes for height if you spefify top and bottom. Using this technique, we can get what we want:

.contentPanel {
    position: absolute;
    left: 200px;
    right: 0;
    top: 400px;
    bottom:0;
}

But the story doesn't end here. Although this technique runs fine in (standards mode) IE7, IE6 does not support it. For this browser, we will use an even rarer technique: expression().

expression() is an IE-only CSS statement that works a lot like calc() mentioned above. With it, you can assign the result of a JScript expression to a CSS property. In our case:

.contentPanel {
    width: expression(this.parentNode.clientWidth - 200 + 'px');
    height: expression(this.parentNode.clientHeight - 400 + 'px');
}

An example

Let's create an example to illustrate the two techniques and how to combine them. Here's a set of three panels, the top one fixed height, the left one fixed width, the remaining one flexible:

#panelTop
#panelLeft
#panelRight

Click the buttons to set the total width.

As you can see, #panelRight fills up whatever space remains. Its CSS is very simple:

#panelRight {
    top:20px;
    left:100px;
    right:0;
    bottom:0;
    width:expression(this.parentNode.clientWidth - 100 + 'px');
    height:expression(this.parentNode.clientHeight - 20 + 'px');
    background:#F7CCF7;
}

Issues

expression Is of course a non-standard CSS property that will invalidate your CSS file. Browsers that don't support it will gracefully ignore it (as they should) but the W3C CSS validator will not. There are several ways to hide the code from validators (i.e. conditional comments) so if you care about validating your CSS you should take some extra steps there.

Another issue is that I haven't found a way yet to combine multiple flexible panels horizontally or vertically. The method works beautifully, however, in my experience and makes it really easy to define flexible page layouts with just a few lines of CSS and the most basic HTML.

Have something to say about this post? Share your thoughts!