Grow your CSS skills. Land your dream job.

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

Comments

  1. Permalink to comment#

    Thank you Chris!
    This is very nice, I will shoot you credit for this on my site.

  2. Permalink to comment#

    Hey Chris,

    Very nice idea. I’ve run into this situation so many times. It’s nice to see a useful scenario like this.

  3. Permalink to comment#

    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 http://css-tricks.com/contact/ page for instance.

    • that’s a good point James

    • Permalink to comment#

      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.

  4. Aaron
    Permalink to comment#

    Would be great with infinite scroll…

    • Bert de Vries
      Permalink to comment#

      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.

    • Bert de Vries
      Permalink to comment#

      I bet the slider thingy would make a good start….

  5. Permalink to comment#

    i think…you are doing well…but some how you’d better change your way

  6. 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.

  7. Sam
    Permalink to comment#

    Chris this really rocks! Chris rocks!!!!!

  8. Permalink to comment#

    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?

    • AC
      Permalink to comment#

      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?

    • AC
      Permalink to comment#

      A good article on the reason is over at Nettuts+. Hope this helps.

  9. Rod
    Permalink to comment#

    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.

  10. Permalink to comment#

    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.

  11. Final Cut Studio
    Permalink to comment#

    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!

  12. 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.

  13. Permalink to comment#

    Great article, thanks. Big fan of using asynchronous calls to a proxy for various things.

  14. Permalink to comment#

    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.

  15. middric
    Permalink to comment#

    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.

  16. 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.

  17. 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

    • Permalink to comment#

      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.

  18. Permalink to comment#

    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.

  19. reijo
    Permalink to comment#

    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.

  20. Permalink to comment#

    amazing…..speechless :)

  21. Permalink to comment#

    Cool article actually! What do you use for code highlighting?

  22. Permalink to comment#

    Fantastic articles. thanks for the useful tips Chris.

  23. Permalink to comment#

    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.

  24. Permalink to comment#

    Very useful, thanks Chris!

  25. Permalink to comment#

    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 :).

  26. Jean-Marc
    Permalink to comment#

    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.

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".