A Better Way to Sticky Content with Javascript

August 31st, 2009 by Cole Thorsen

sticky-content

Content that scrolls with the browser window is not a new concept. We all know how to position things relative to the browser window with position: fixed; However what if we only wanted it to stick the browser window conditionally? Most of the time I see this in practice, the developer has used Javascript to reposition the container absolutely so it always appears within the constraints of the users current window position. The problem with this method is that it causes the stickied content to jitter as it slides down (or up) the page. This can be extremely irritating to the end user. Let’s see an example of the incorrect method.

In order to smooth, rather than re-positioning this sticky content every time the user scrolls, we can change the positioning type from relative or absolute to fixed. This will fix the content to the browser window and allow it to scroll smoothly. Essentially what we are doing is changing the CSS once whenever the user scrolls far enough down the page to need the desired effect rather than changing the CSS every time the user scrolls. Let’s see an example of the proper method.

Here’s how to do it.

First the CSS: position the sticky content to its original location

#sticky {
    position: relative;
    height: 600px;
    width: 300px;
}

Building the Javascript.

I am using jQuery to make it faster and easier to build, since we include jQuery on pretty much everything we build. Doing it this way will make a lighter footprint than building it in straight javascript. Therefore we will need to invoke jQuery - we tend to use Google AJAX Libraries for this.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>

First set the parameters for the sticky: We need to know how high the sticky will be; if it is higher than the user’s browser window then we cannot scroll it because they would never see the bottom content. Next we need to know if there is any padding necessary at the top and bottom of the element when it is stickied. Finally we need our offset from the top and the height of any footer elements that we do not want to cover up.

var $stickyHeight = 600;
var $padding = 10;
var $topOffset = 200;
var $footerHeight = 83;

Now lets set up a framework for the rest of the javascript. We will build a function to handle the lifting and then invoke it using jQuery’s $(window).scroll() function

function scrollSticky(){

}

$(window).scroll(function(){
    scrollSticky()
});

Now we need to set up the conditional logic to determine which of the three states the sticky should be in (bottom position, sticky or top position). This is all wrapped in a conditional statement to test to see if the users browser window is tall enough to support the sticky.

function scrollSticky(){
    if($(window).height() >= $stickyHeight) {

        if($(document).height() - $footerHeight - $padding < $(window).scrollTop() + $stickyHeight) {

        }else if($(window).scrollTop() + $padding > $topOffset) {

        }else{

        }
    }
}

Finally we are ready to manipulate the CSS of the document so the sticky is positioned correctly for each of the 3 states.

function scrollSticky(){
    if($(window).height() >= $stickyHeight) {
        var aOffset = $('#sticky').offset();

        if($(document).height() - $footerHeight - $padding < $(window).scrollTop() + $stickyHeight) {
            var $top = $(document).height() - $stickyHeight - $footerHeight - $padding;
            $('#sticky').attr('style', 'position:absolute; top:'+$top+'px;');

        }else if($(window).scrollTop() + $padding > $topOffset) {
            $('#sticky').attr('style', 'position:fixed; top:'+$padding+'px;');

        }else{
            $('#sticky').attr('style', 'position:relative;');
        }
    }
}

Lets see it all together.

<script>

var $stickyHeight = 600;
var $padding = 10;
var $topOffset = 200;
var $footerHeight = 83;

function scrollSticky(){
    if($(window).height() >= $stickyHeight) {
        var aOffset = $('#sticky').offset();

        if($(document).height() - $footerHeight - $padding < $(window).scrollTop() + $stickyHeight) {
            var $top = $(document).height() - $stickyHeight - $footerHeight - $padding;
            $('#sticky').attr('style', 'position:absolute; top:'+$top+'px;');

        }else if($(window).scrollTop() + $padding > $topOffset) {
            $('#sticky').attr('style', 'position:fixed; top:'+$padding+'px;');

        }else{
            $('#sticky').attr('style', 'position:relative;');
        }
    }
}

$(window).scroll(function(){
    scrollSticky()
});
</script>

Tags: , , , ,

Share this page


5 Responses to “A Better Way to Sticky Content with Javascript”

  1. Thanks for the walkthrough, I’ve been looking for this for a while.

    I made a slight change in the code, to make it work better for me:

    var $stickyDiv = $(”.etest_builder-recap”);
    var $stickyHeight = 600;
    var $padding = 10;
    var $topOffset = 200;
    var $footerHeight = 83;

    $(window).scroll(function(){
    if($(window).height() >= $stickyHeight) {
    var aOffset = $stickyDiv.offset();

    if($(document).height() - $footerHeight - $padding $topOffset) {
    $stickyDiv.attr(”style”, “position:fixed; top:”+$padding+”px;”);

    }else{
    $stickyDiv.attr(”style”, “position:relative;”);
    }
    }
    });

    Thanks again.

  2. Cole Thorsen says:

    @Gabriel no problem. Looks like you’ve simplified it a bit and removed the footer limit. I should have thought of moving the div name itself to a variable like that. Makes more sense for the demo than having it in the code.

    Nice to see it was useful, I’d love to see the finished product.

  3. hmmm says:

    Hmmm, nothing scrolls on both examples on FF 3.6

    • Cole Thorsen says:

      Seems to be working fine in Firefox 3.6 for me.

      The Javascript has a conditional statement in it that monitors the height of your browser window. If your browser window is not high enough to view the entire content of the scrolling area it will not scroll (so users with small browser windows can still see all the content). You could be experiencing this if you are not seeing it scroll.

      To remove this section of the javascript remove the line:

      if($(window).height() >= $stickyHeight) {

      and of course its corresponding closing brace.

  4. hmmm says:

    Working fine now ;)
    Thanks

Leave a Reply

Get in touch…

Mailing Address

201-66 Bay St. S
Hamilton, Ontario L8P 4Z6

Phone Number

519.933.9505

Satellite Office

565 Proudfoot Lane
London, Ontario N6H 0A1

Have a general comment or suggestion? Find us on: Get Satisfaction

close