Sunday, August 26, 2012

CSS Recipe for Making Elements Fill Their Container Height

A common desire when designing Web sites is to have a columnar layout, with something along the lines of a sidebar that is visually distinct from the main content, but which fully consumes the space.  This can be surprisingly difficult to implement consistently, and leaves many designers reaching for a background image on the container, even if only solid colors are required.  A more flexible solution is available using CSS and HTML alone (not even JavaScript is required)

Quick Disclaimer

Honestly my single biggest reason for this workaround is that I loathe having to open up a graphics editor for something like this, particularly to only perform a slight adjustment   I'm also neurotic enough that I want the static resources associated with a site to be truly relevant, so that even one file that is conceptually redundant irks me.  This workaround isn't pristine as it throws an element in the HTML which is solely for design purposes, though at this point I'm also increasingly viewing the DOM as the optimal place to pollute in little ways in the interest of keeping other more complicated aspects simple and organized. This solution is also limited to some scenarios.

Also as a quick note I'm writing this in HTML but I'm not doing it in any way orderly since I'm just typing into blogger, so inspect the elements rather than reading the source.

The Problem

Pretend for a moment that this container is a full document body as displayed in a browser
And you want to put another container in it, we'll use a sidebar since it's relevant:
Sidebar Content
But that's no good, so we set the height of the sidebar to be the full height of the container using height:100% and making sure the container is position:relative:
Sidebar Content

Looks good...until

Sidebar Content that is really long and no longer fits in the size that the container was originally assigned to and ends up spilling out of the edge
Now here's where the imagination kicks in, that's broken because the content jumps out of the background (and you can pretend you'd scroll down to view that area that is outside of the container). But not to worry...CSS has you covered, change the height:100% to min-height:100%...then the container will always be at least the full height but will expand to hold its contents.
Sidebar Content that is really long and no longer fits in the size that the container was originally assigned to and ends up spilling out of the edge
Problem solved, and you picked up a new CSS trick. More realistically though the main container will also be sized by percentage so it can scale to fit the visitor's screen (otherwise that's another issue), so we'll add some content to that area and change the height to a relative one.
Sidebar Content
Main content with all sorts of interesting facts that are normally longer than the sidebar content.
Argh...back to square one.

The Solution

So I went back and forth with this issue for a little bit like probably most people have that tried to solve it with CSS alone. Every solution seemed to break when either the sidebar or the content area was larger, or when things happened like the page scrolling. Finally one day I had the forehead smacking realization (and this is where it gets slightly kludgy) why not just do both? Not ideal, but for me still preferable to a background image. When we last left the code it was left in a state where the sidebar would grow to hold the contents, but would not consistently fill the content area. This is more relevant from the DOM perspective as it flows properly, so we can leave that one alone...but then add a second element behind that one that consistently fills the container. For that you need to use an alternate positioning type: the often maligned "absolute" positioning, and in this case combined with constraint based positioning (alternate sizing options would also work). Adding a sibling element beneath the sidebar on the z-index within the same position:relative parent element...with absolute positioning, the same width as the sidebar, and a 0 value for in this case, top, right, and bottom to have it fill up the entire right side.
Sidebar Content
Main content with all sorts of interesting facts that are normally longer than the sidebar content.
So that now checks out...now the other way around:
Sidebar Content that is really long and no longer fits in the size that the container was originally assigned to and ends up spilling out of the edge
Main content with all sorts of interesting facts that are normally longer than the sidebar content.

(Again pretending you would scroll down to see that part overlapping the "window"). And...perfect(ish). So long as your DOM is in decent shape this works like a charm and has been put through the paces on several sites and seems to be quirk-proof in major browsers. This could also be handled by JavaScript on page load. Overall a slightly more complicated solution than a background image and may not be for everyone...but it is likely more maintainable and is also arguably more conceptually accurate than attaching the primary visual representation of one element to a resource associated with another element.

Quick Amendment

I realized after I wrote this that it is missing another piece: that container should expand to hold the sidebar if needed now that it has a relative height. Since the sidebar is presently floated it's not expanding the container. This can be solved by the typical clearfix workaround.

Sidebar Content that is really long and no longer fits in the size that the container was originally assigned to and ends up spilling out of the edge
Main content with all sorts of interesting facts that are normally longer than the sidebar content.

No comments :

Post a Comment