Skip to content
Skip to content

Creating A Sticky Sidebar

A sticky sidebar both looks snazzy and stops your page from having great big stretches of whitespace on longer posts. But depending on their size and if their content is variable, they can sometimes be tricky to implement.

Quick note on the below. I'll be writing jQuery each time instead of $ to avoid conflicts with Wordpress's jQuery. I usually find it easiest if I'm just working on something short.
You can feel free to wrap you code in:

jQuery(function($) {

});

and then replace 'jQuery' with '$' if you prefer.

The jQuery scrollTop Method

This is the older method, but we'll put it here for posterity.

All of the below methods apply to the theme we use as a base for most of our site (x theme). It uses aside tags for the sidebar, but your theme may use something different (a div with a sidebar class?)

The jQuery


// sticky sidebar

function sticky_side() {
//Get the scroll position and the position of the bottom of the window
var winTop = jQuery(window).scrollTop();
var winBot = winTop + jQuery(window).height();
//Get the top and bottom positions of our sidebar
var elementTop = jQuery('aside').offset().top;
var elementBot = elementTop + jQuery('aside').height();
//Get the top and bottom position of our header elements
var headTop = jQuery('bg_featured').offset().top;
var headBot = headTop + jQuery('bg_featured').height();

//Get the top position of our footer
var footTop = jQuery('footer').offset().top;

//We want the sidebar to be fixed once the bottom of it comes on screen
if (elementBot < winBot) {
jQuery('aside').addClass('sticky-sidebar');
}
// When the footer comes on the screen, we do not want the sidebar to be fixed anymore or it will overlap
if (elementBot > footTop) {
jQuery('aside').addClass('bottomed-sidebar');
}
// When scrolling back up, we want the sidebar to be fixed again
if (winBot < footTop) {
jQuery('aside').removeClass('bottomed-sidebar');
}
// When we return to the top we don't want the sidebar to be fixed anymore or it will overlap over header content
if (elementTop < headBot) {
jQuery('aside').removeClass('sticky-sidebar');
}
}
jQuery(window).scroll(sticky_side);

 

The CSS

Here we need to flesh out the classes we created above.

We also have to make sure our content container is set to relative so that our "bottomed-sidebar" class doesn't just fly off the page.


/* sticky sidebar */
.single-post .x-container.max.width.offset {
position: relative;
}
.sticky-sidebar
{
position: fixed;
bottom: 1.45%;
right: 2.6%;

}
.bottomed-sidebar
{
position: absolute;
bottom: 0.45%;
right: 0%;
}

 

Issues With This Method

  • It's a bit fiddly. You're going to need to figure out positioning for both the fixed and position absolute and get them to match up.
  • Using scroll events can be cumbersome and may slow down your page.

CSS Position Sticky Method

Position sticky is a relatively new way to position elements with css. It's sort of a hybrid of position:relative and postion:fixed. It operates as the former until the


aside {
position:sticky;
position: -webkit-sticky;
position: -moz-sticky;
position: -ms-sticky;
position: -o-sticky;
top: 0;
}

/* Also note that sticky won't work if an ancestor has overflow hidden so we'll override that */

body, div#top {
overflow: visible;
}

 

Issues With This Method

  • Position sticky will get messed up if any of it's ancestors has an overflow:hidden;

In our case, our theme sets:


body{
overflow-x:hidden;
}

 

So we had to override that with:

body{
overflow-x:visible;
}

 

Which has had no ill effects. But this is likely because them theme is put together well enough, so we're not encountering any overflows anyway.

  • The sticky position is fixed.

You have to set a fixed position to tell the element where to stick (top:0px;).
Which is fine if your element is both smaller than the window height and of a fixed size.

If it's bigger than the window size (as our sidebars often are), it's likely going to 'stick' the top part of the sidebar content to the screen until you get top the bottom part of the page. Or worse still it may 'stick' somewhere in the middle of the sidebar content.

You might be able to work around this if your sidebar was of a fixed size by fiddling around with your top value. say if you had a sidebar that was 900px tall, you could set a top value of -450px. That way the sidebar would only 'stick' once 450px of it was off screen.

But that won't be of any help if your sidebar content is of variable height. Furthermore, you might still have issues with where the sidebar sticks on varying screen sizes.
It's not the end of the world, the content at the bottom of the sidebar will show up once the user scrolls far enough. But it's not the smoothest looking implimentation.

The jQuery/CSS Position Sticky Method

This clean little solution is the best of both worlds. It avoids all the clunkieness of the jQuery scroll method. But it also dynamically figures out the height of our sidebar, so it knows just where to 'stick' it so that it holds exactly when the bottom of the sidebar comes on screen and not before.

It'll achieve this by using jQuery to get the height of the sidebar and then subtracting the height of the window from it. Then it'll set the top value of the sidebar to minus the remainer (plus twenty in our code to give us a nice little bit of margin, not just content flush to the window)



// Blog sidebar

var sideBar = jQuery('aside').height();
var winHeight = jQuery(window).height();
var newHeight = (sideBar - winHeight) +20;
var minus = newHeight * -1;
jQuery('aside').css('top',minus);

 

Don't forget to add your position sticky to your CSS


aside {
position: sticky;
position: -webkit-sticky;
position: -moz-sticky;
position: -ms-sticky;
position: -o-sticky;
}

/* Also note that sticky won't work if an ancestor has overflow hidden so we'll override that */

body, div#top {
overflow: visible;
}