CSS Quiz Review: The iPhone Challenge, a Collapsible Multi-column Layout

    Bernard Peh

    In a recent quiz in the SitePoint CSS forum, I set the following challenge: create a full-width layout made of three columns that align vertically underneath each other when the browser is resized to around 320 pixels. The columns were to be in source order, so that they would be in the same order in the source as in the horizontal and vertical layouts.

    The premise I set out was that the method could be used for viewing normal width sites on an iPhone without having to have a separate style sheet or multiple rules for the device. Later I found out that some additional styles were required to make this work on an iPhone, and I’ll go into more detail about that at the end of the article.

    As with all my quizzes, the implementation on the iPhone was really secondary; all I really wanted to achieve was a three-column layout that would align into one column at about 320px browser width in all modern browsers. Being without an iPhone, I tested the layout in Apple’s iPhone tester.

    In this short tutorial, I’ll run through the techniques needed to accomplish this feat, and stop along the way to explain the why and how in more detail. You can follow along by downloading the sample code archive.

    A First Attempt

    At first sight, you might think that this effect would be easy to achieve, but it actually turns out to be quite involved.

    In order for the page to be full width, I allowed the left and right columns to be a fixed width, with the center column fluid to fill the remaining width of the browser window.

    Usually in a three-column layout, the first column is floated left and the second column is floated right; the middle column is last in the markup, and has left and right margins to clear the floats and form a rectangular box to the side.

    We’ll start by looking at the most basic way of doing this. Ignoring hasLayout issues and the IE6 3 pixel jog, the code would look like the following.

    First, the CSS:

    Example 1. example1.htm (excerpt)

    .column1 {  width:300px;  background:red;  float:left;}.column2 {  background:green;  margin:0 310px;}.column3 {  width:300px;  background:blue;  float:right;}

    The basic markup structure looks like this:

    Example 2. example.htm (excerpt)

    <div class="column1"></div><div class="column3"></div><div class="column2"></div>

    The result of these styles is a layout like the one shown in Figure 1, “Our three-column layout”.

    Figure 1. Our three-column layout

    Our three-column layout

    This gives us the basic three-column layout we were looking for, though the columns are in the wrong order in the source code. Let’s deal with that later, and instead first concern ourselves with what happens when the browser window is resized horizontally.

    It turns out that the left and right columns start to line up vertically quite well, but the middle column is squashed and out of place, as shown in Figure 2, “The layout breaks when the browser is resized horizontally”.

    Figure 2. The layout breaks when the browser is resized horizontally

    The layout breaks when the browser is resized horizontally

    This behavior is unsurprising: the middle column has margins on the left and right, and therefore can never move to the edge of the screen, unlike the floated content that will drop down and align to the side.

    Because we’re unable to have the middle column line up on the left side of the window, we’ll need to abandon this method and try a different approach.

    Back to the Drawing Board

    Instead of using margins on the middle column, we could instead try to make use of the overflow property. The following technique removes the margins from the middle column completely and applies overflow: hidden, which has the effect of creating a rectangular unfloated column that slides between the two floated columns.

    When an element has overflow: hidden (or auto) applied, it will no longer wrap around a floated element; instead it wraps alongside it in a rectangular block, almost like another float.

    Unfortunately, IE6 doesn’t understand this behavior. Luckily for us the same effect can be achieved by simply ensuring the element is in hasLayout mode; it then behaves as we want, and slides between the two floated columns in a rectangular block.

    The markup remains the same as before, but the CSS for column2 changes as follows:

    Example 3. example2.htm (excerpt)

    .column2 {  background:green;  overflow:hidden;}* html .column2 {  height:1%;  overflow:visible;}

    Note that we’ve triggered hasLayout with the height: 1% hack, but at the same time we must set overflow back to visible; otherwise, we run the risk of all content above 1% being hidden. In this case there’s no issue, as the 1% has nothing to base its height on, and so is effectively auto. As a result, nothing would be hidden—but this may not always be the case, so it’s best to take this precaution.

    The result of these styles is that we achieve the three-column effect without the need to use margins. The page will now look much the same as Figure 1, “Our three-column layout”.

    If we then squeeze the browser even smaller, we find that in all versions of IE the three columns line up nicely in one column, as shown in Figure 3, “A three-column layout collapsed into one column on Internet Explorer” below.

    Figure 3. A three-column layout collapsed into one column on Internet Explorer

    A three-column layout collapsed into one column on Internet Explorer

    Unfortunately, neither Firefox nor Safari display this layout correctly. Both of those browsers leave the middle column hanging to the side and spoil the party.

    It seems that we’re again running down a dead-end road, and so we need to think of another solution. We also have to remember that the task was also to have the columns in source order, which neither of our solutions to date has achieved.