Tuesday, May 29, 2012

Responsive full height (equal height) columns using the faux columns css technique

Source code on GitHub

First things first, here is  the source code.
View project on GitHub

Introduction

In this tutorial I'll show you how to create responsive full height columns using the "faux columns" technique.
There are 3 main concepts in that:
  1. Full/Equal height: When you float an element, its height is equal to its content; not to its "context". This causes a problem if you want a sidebar that has a different background-color than the main area because the background will not extend to the same height as the other column(s).
  2. Faux column technique: This is a technique that uses a background-image to create an effect that looks like the column extends to the full height. This technique has been documented several times but this article is a bit different because of the following point.
  3. Responsive: With responsive design, the width of the page set to a fixed size (such as 960px). Instead the content of the page adapts as your make your browser window wider or narrower.
So this tutorial is about using the faux column technique but with the necessary tweaks to make it work in a responsive layout.

The HTML:

The page has a header div, a main div and a footer div. The main div has an article div and a sidebar div on the right side.
<body>
    <div class="page">
        <div>
            header 
        </div>
        <div class="main clearfix">
            <div class="article">
                Main content
            </div> 
            <div class="sidebar">
                sidebar
            </div>
        </div>
        <div>
            Footer
        </div>
    </div>
</body>

The CSS:

1 - Define the clearfix class to help us clear the float.

There are several ways to clear floats. The technique I use here it the one used in the HTML 5 Boilerplate project. See this blog post to learn about that specific technique.

.clearfix { *zoom: 1; }
.clearfix:before, .clearfix:after { display: table; content: ""; }
.clearfix:after { clear: both; }  

2 - Define the two columns using a 70/30 ratio.

.article {
    float:left;
    width:69%;
    padding-right:1%;
    overflow:hidden;
}

.sidebar {
    float:right;
    width:28%;
    padding-left:1%;
    padding-right:1%;
    overflow:hidden;
}

Setting the overflow to hidden is not mandatory but I think it looks better when you resize the browser so small that content cannot be wrapped.

3 - Add the faux column effect by setting a background image

This is the key part.

.main {
    background: url(opaque-0.70-5000.png)  
                repeat-y                   
                70%                        
                top;                       
}

Note that:
  • The background image is set for the main div; not the sidebar div.
  • The background image is 5000px wide by 1px high.
  • The width of the image determines the maximum width that your page will support; beyond that point the faux column effect will break (you can use a larger image if you want but 5000px is really wide).
  • The height of the image does not matter. If you use an opaque color, then 1px is enough. If you want to use a pattern then you can use a taller image.
  • In the image, the column start at 70% of the width of the image, at pixel 3500 (5000 * 0.7 = 3500).
  • The 70% value in the css is the position of the image. Use the same value as the ratio.
This works with any image width. The only thing that matters is you have to start the column effect at the right pixel. For example, if you have a 3000 pixel wide image, your column effect should start at pixel 2100 (3000 * 0.7 = 2100). This example does not fill the right side; there is just 1 pixel at position 2100, which create a vertical line.

.main {
    background: url(line-0.70-3000.png) 
                repeat-y                  
                70%                       
                top;                      
}

4 - Set a max width for page and add some spacing

As stated in the previous step, the width of the image determines the maximum width the page support. To ensure it will not break beyond that point I set a max-width on the page div. If you don't like the way your site looks when it is very wide, you can set a max-width of 1600px (that's what I usually do).

.page {
    width:75%;         
    margin:auto;       
    max-width:5000px;  
}

5 - Responsive with media queries

You can use css media queries to change the ratio of the columns based on the browser width and for the faux column to work, you will have to change the background image too. For example, if you want a 75/25 ratio when the page is narrower than 600px, you have to:
  1. Create a background-image with a ratio of 75/25. For a 600px wide image, the column must start at pixel 450 (6000 * 0.75 = 450).
  2. Add media query, change background-image and change the column ratio:
@media screen and (max-width: 600px)
{
    .page {
        width:95%;          
        margin:auto;        
        max-width:600px;              
    }
                
    .main {
        background: url(opaque-0.75-600.png)
                    repeat-y               
                    75%                    
                    top;                   
    }

    .article {
        float:left;
        width:74.5%;
        padding-right:0.5%;
    }

    .sidebar {
        float:right;
        width:24%;
        padding-left:0.5%;
        padding-right:0.5%;
        overflow:hidden;
    }
}

Conclusion

I learned a lot in the process of writing this post. I don't consider myself an expert on the matter. Don't hesitate to leave comments if you think the solution can be improved and I will update the post accordingly.

Don’t forget that you can browse the code on GitHub.

11 comments:

  1. Is there any reason to use the image over the min-height css attribute?

    ReplyDelete
    Replies
    1. Do you mean setting a min-height on the sidebar div instead of using the faux column technique? What value would you set it to? You don't know in advance how high the article div will be. You could use javascript to set it when the window is resized. But that would be a completely different technique.

      Delete
  2. There seems to be a problem if the sidebar has long content than the main.

    Basically, I was trying to create a two-column gallery with variable contents. If the left column has long content than the right, then it will be fine. However, if the right column has long content than the left, then the proceeding columns will move to the left columns.

    Here's a test case for my scenario: http://jsfiddle.net/L2Mrq/

    ReplyDelete
    Replies
    1. Hi, You cannot use 'article' and 'sidebar' classes to create sub sections. You can only have one 'article' and one 'sidebar' per 'main'. If you want to split your article content or your sidebar content you can use any other div. For instance, see the div and hr that separate the sidebar in this example http://jsfiddle.net/L2Mrq/7/. Finally, you can have multiple 'article' and 'sidebar' if you have multiple 'main' as in http://jsfiddle.net/L2Mrq/2/.

      Delete
  3. This doesn´t work if you put an image in the sidebar.

    ReplyDelete
  4. I just wanted to say thank you, I've used this technique on a site I'm currently working on :)

    ReplyDelete
  5. Thank you for this site. your totally help me to create my site http://easydomainfree.blogspot.com/

    ReplyDelete
    Replies
    1. I'm glad it helped. Thanks for leaving a comment.

      Delete
  6. You rock! Thank you so much for this solution. I worked with faux columns before - but in a responsive design it's a different story. So, thank you! You made my day :-)

    ReplyDelete
  7. thank you .. You did it !
    It was awful to find the "Right solution" for responsive layout and you save me hours.
    so thank you again !
    olivia

    ReplyDelete