Load More Sidebar Content When There Is Room

Published by Chris Coyier

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.

Classic problem.

Possible solution.

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.

View Demo   Download Files