One classic layout conundrum is how much stuff to put in a sidebar. Ideally the height of the main content area and the sidebar are about the same, to avoid either area having a large blank area which can be strange looking and a waste of good web real estate. Go light on sidebar content and short content pages may be just about right but long content pages have a lot of unused sidebar space. Go heavy on sidebar content and those long content pages are looking good but short content pages are pushed down awkwardly far.
One solution is to pick some kind of happy medium and just roll with it. Another is to get technical and dynamically load the appropriate amount of sidebar content to fit the space available. Let’s look at how you might do that.


Testing Heights
We literally need to measure the height of content here, so that’s JavaScript territory. I’ll be using jQuery. So let’s say we have:
<section id="main-content">
</section>
<aside>
</aside>
First we’ll “cache” those elements so we don’t need to select them more than once.
var
mainContent = $("#main-content"),
aside = $("aside");
We are going to need to repeatedly test the height of the aside
(sidebar) so we don’t need to cache that height, but let’s make a variable for the height of the main content area which will not be changing.
var height = mainContent.outerHeight();
Now we’ll run a little test and and see if the sidebar has any room for more content or not (in otherwords, has a lower height value than the main content area):
if (height > aside.outerHeight()) {
// load in more sidebar content
}
Loading in the modules
Using a JavaScript library like jQuery makes Ajax loading of content pretty easy. If you hade a file called sidebarmodule.php
which contained the markup for an additional piece of sidebar material, you could load it in like this:
$.get("sidebarmodule.php", function(data) {
// Create sidebar box
$("<div />", {
"class" : "sidebar-box",
"html" : data
// Fade in new module
}).hide().appendTo(aside).fadeIn();
});
But that only handles a single module. I like the idea of having a bunch of modules ready to be inserted as needed, and also keeping them contained within one file for simplification. So let’s make the sidebarmodule.php smarter and be able to return the correct module based on a GET parameter.
<?php
$module = $_GET['module'];
if ($module > 3) { echo "No more modules"; return; }
echo "<h3>Sidebar Box #$module</h3>";
switch($module) {
case 1: ?>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>
<?php break;
case 2: ?>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>
<?php break;
case 3: ?>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>
<?php break;
default:
// Shouldn't ever get here, but just in case output some kind of error
echo "<p class='error'>No more modules</p>";
}
?>
Now we’ll pass that integer parameter along when we make the Ajax request to specify which one we’d like returned. Notice how we’ve only created three modules as well? Let’s make sure that we don’t do anything if we get back a response that there isn’t any more modules left:
var module = 1;
$.get("sidebarmodule.php", { "module": module }, function(data) {
if (data != "No more modules") {
module++;
// appending and whatnot
}
});
A few cleanups to do
We’re going to need to recursively do this Ajax request for more modules when we run a test and verify there is room for more modules. So what we’ll do is abstract it into a function, then call that function again if need be. We also need to ensure that the recursion stops if we’ve run out of modules, so we’ll set up a done
variable that is a stopper if we get the “No more modules” response from the script.
Lastly, we’ll set up a buffer variable for the height. If the sidebar is only shorter than the main content by like 3 pixels, we really don’t need another whole module, so we’ll set this buffer to like 80 pixels so another module isn’t loaded unless the sidebar is shorter by at least that.
Here is the whole shebang:
var mainContent = $("#main-content"), /* "Caching" */
height = mainContent.outerHeight(),
aside = $("aside"),
module = 1, /* Start with the first, increments */
buffer = 80, /* To prevent sidebar from growing way taller than main content if it's only barely shorter */
done = false; /* If no more modules to be had */
function getMoreContent() {
$.get("sidebarmodule.php", { "module": module }, function(data) {
if (data != "No more modules") {
// Increment # so next time it will grab a differnet module
module++;
// Create sidebar box
$("<div />", {
"class" : "sidebar-box",
"id" : "sidebar-box-" + module,
"html" : data,
"css" : {
"position": "relative",
"left": 25
}
// Fancy revealing of new content
}).hide().appendTo(aside).fadeIn(200, function() {
$(this).animate({
"left": 0
});
});
// If after getting new module, sidebar is still too short, start over
if ((height > (aside.outerHeight() + buffer)) && !done) {
getMoreContent();
}
}
});
}
// Initial test
if (height > (aside.outerHeight() + buffer)) {
getMoreContent();
}
Notes on Usage
I’m not yet using this idea on this site, but I’m going to think about it, as it’s a pretty good example of a site that could benefit from it. One of the considerations is content that requires JavaScript in it, for example the Poll on this site. It’s still certainly possible to use, it just needs to be made sure that JavaScript events are bound to the incoming elements and thus requires a little more tinkering and thought.
SEO experts may also want to weigh in here. I have no idea the implications of this. Does Google (or other search bots) see this dynamically added content? I would think not, but sidebar content is likely not important for that anyway, and may in fact be good that Google doesn’t see it (higher percentage of content on the page related to actual topic of page).
Demo & Download
Note there is some PHP at play here, so don’t expect to download this to your desktop and have it work, it’s gotta be somewhere the PHP can actually run.
Thank you Chris!
This is very nice, I will shoot you credit for this on my site.
I second this, I’d like to see that tutorial…
We use dynamic sidebar modules (and footer modules) on all the wikis hosted at Wikia… We use a combination of server side logic and JS to detect page height and build nice looking results for pages which have highly variable amounts of content on them (since they are user generated).
Google will now index content which is normally only visible via Ajax, which is probably another good idea for a tutorial. :)
http://code.google.com/web/ajaxcrawling/docs/getting-started.html
Doing it server-side is neat too. I could picture doing word-counts of articles and then outputting modules according to that count. Or perhaps getting a bit more sophisticated and measuring images as well.
—
That
_escaped_fragment_
stuff in the Google article is interesting. That would definitely be a good bit of work setting all that up.Looks like Twitter’s work? https://twitter.com/?_escaped_fragment_=/1Password/statuses/17325144028479488
Yeah doing it server-side, reminds me of Jonathan Snooks article from back in 2007, doing this with CakePHP : http://snook.ca/archives/cakephp/elemental_conditional_content_with_cakephp
I think doing it with a js implementation is more fun though :)
Chris,
You could always load all the content into hidden sections and use JS to show/hide them with the height.
This would allow google to see all the content no matter how tall the page was, and you don’t have to mess with ajax :)
That sounds like what I was thinking when I originally say the article title. What would be your plan of action for implementing that method, TechWraith?
Hey Chris,
Very nice idea. I’ve run into this situation so many times. It’s nice to see a useful scenario like this.
I like the idea, but I’m wondering if the opposite approach might be better. Load in all the sidebar content, and then hide modules based on main content height. If the user doesn’t have JavaScript enabled, they’ll see everything, and that should cover the SEO concerns as well. It would be quite a bit simpler as well since you don’t have to make any AJAX requests.
Yeah I would prefer that as well. (Y)
The problem with this is that if something on the page takes a longer time to load content blocks will disappear once the javascript is loaded. It might leave the visitor wondering where it went.
Great article.
To be honest, I very much like all of that empty space you get in the sidebar when the page’s content is very long. It keeps me focused on the content I came to view.
However, I do think that pages with sidebar content that far surpass the main content in length would benefit from being snipped. Like on your https://css-tricks.com/contact/ page for instance.
that’s a good point James
This is my thinking as well. I recently did a website port of a magazine, and I used the whitespace under the navigation bar on the left to fade in a “back to top” box once the user scrolled down a bit past the sidebar; a much better use of space in this instance that putting in more content.
However, that’s not to be needlessly negative about this trick; it’s quite cool, and would certainly be appropriate in some instances. (for example, presenting additional ads on a lengthy page while leaving shorter pages without the extra clutter) But I do think that some people lean towards filling whitespace that would be better served by being open.
Would be great with infinite scroll…
I really like this idea. A vertical scrolling sidebar. Segments gracefully disapearing at the top and the whole sidebar moves up, while segments are added at the bottom. When there are no more segments left start over with segment number one at the bottom. Preferrebly stays within the browser window. When sidebar is in focus (mouseover?) it would be nice to control the scrolling with your mousewheel. Make sense?
I wish i could create such a thing. Would make a beautifull screencast (wink wink)
Greetings to all of you. Have a nice Xmas and a happy new year.
I bet the slider thingy would make a good start….
i think…you are doing well…but some how you’d better change your way
This is really awesome! Something else that might work (in WordPress) is getting the word count and then running an if statement, thus getting rid of the need for JS. If you’re running a caching plugin then the impact should be minimal, too.
Great idea though :)
Problem I see with counting words is that you can’t really tell the height. What Chris already mentioned, images and other things play a significant role in the height. Which means it won’t be that accurate.
Chris this really rocks! Chris rocks!!!!!
Really cool idea! And I suppose if JS is disabled, the sidebar simply won’t display any extra items, so it degrades nicely.
Off-topic: I wasn’t aware you could declare multiple variables in jQuery by using a comma-separated list. Does that work in traditional JS too, or is that a feature specific to jQuery?
Yes that’s a javascript thing, advisable by jsLint – “Allow one var statement per function” option. I think it looks cleaner and easier to read. I am not sure if it benefits performance, would be interesting to see if someone else knows?
A good article on the reason is over at Nettuts+. Hope this helps.
Nice trick!!
As long as some comfortable ‘white space’ is left to keep everything clean and pretty I love the idea.
Another similar approach I’ve seen lately is to fix the sidebar: when the user scrolls down the page, the sidebar scrolls down too. Here’s an example done with CSS and JavaScript: http://xaviesteve.com/agile-scrum-google-spreadsheet-template-for-freelancers/
Strange thing is that Flash objects ‘blink’ when the CSS property changes, guess it’s due to the DOM being repainted/redrawn.
I think it is better to leave that space in the sidebar empty because that improves readibility – being conscious of your reader’s needs builds trust, it is better to keep the screen simple in the middle area where the user is reading.
Great post, thanks! Would this situation work on mobile devices? I’ve noticed on my iPhone that text isn’t rendered the same and sidebars can appear shorter due to text in the main content area rendering larger. I would assume the JavaScript would detect the height accurately on the device you’re using?
Thanks again!
I recently implemented something like this on my blog article pages. Since loading random modules doesn’t make sense for my site, I am loading ads. The code is a little different but the idea is the same, measure the content area and add the tallest ads possible, up to 2 ads, to fill the remaining space if any exists.
See it in action here: http://af-design.com/blog/ and click on any article.
Great article, thanks. Big fan of using asynchronous calls to a proxy for various things.
But there is a problem by including a sidebar in certain pages. It will reduce the focus on the page content. Visiters may navigate from the links in the sidebar. Suppose if we include a side bar in a product page, people may navigate from that page through the sidebar links and the products will not be noticed. I got this point from some podcasts and I strongly agree with them.
Caching the jQuery objects is a good idea but in this case you really dont need to cache the #main-content.. you’re only pulling out its height once so just store the height, otherwise you’re actually degrading the script performance.
Don’t really agree with this idea, most of the time this “problem” shows itself when trying to read a long article, I like the fact that after some scrolling pretty much all the distractions are taken away. There is nothing in a sidebar for me to want to look at if I’m trying to read a long article.
I think this sort of thing does have a use, but not just to fill space for the sake of filling space.
Hi Chris
As always, great article. The only thing I’ve noticed is that you “forgot?” the $ code convention: if it’s a jQ object, prefix the var with $, don’t otherwise.
Is it a new thing or just this article?
Very interesting point of view, as well as some good ideas on the comments too. Your site is getting cooler and cooler with time. :)
All the Best
Wolff
Some people prefer not to prefix jQ objects with $ as it’s too much like hungarian notation in their opinion.
I’ve personally stopped following that convention.
I also like this idea with the caveat that it doesn’t detract from the main content. Sometimes, especially on blogs, it feels like a mine field trying to navigate around the ads in order to read a post.
Love the idea of the AJAX hit to display “real” content or something that adds to the user experience.
Im currently working on jquery plugin that you can use to tag containers so when scrolling down, some important elements in the sidebar changes to fixed and follows down. Will use it for related articles.
amazing…..speechless :)
Cool article actually! What do you use for code highlighting?
Fantastic articles. thanks for the useful tips Chris.
This is exactly what I’m looking for.
Im going to use this on some future projects and make sure you get appropriate accreditation.
Thanks for another good post.
Very useful, thanks Chris!
I’d like to stop for a while on SEO point of view. I know that some “experts” will tell that this solution is wrong. But, like you mentioned in the end of the post – sidebar is not important thing! If you design your site, you shouldn’t be worried about “how about Google?”. Believe me, if you create good site, tip, solution, etc., user will find. Always :).
Hi,
I don’t understand where the “done” variable is set to true ?
May be an else block is missing on the “if (data != “No more modules”)” ?
Anyway, great tutorial, very usefull and easy to understand !
Looks like I was trying at one point to use a done variable but didn’t end up needing it and didn’t take out that code. What happens is that if the height ends up taller, it just never calls itself again and that’s how it stops.