Search code examples
javascripthtmlcssmootoolssticky

Multiple sticky side blocks in dynamic page


I have a page where in the content area a dynamic number of rows are generated. Each row has two columns: a side block and a content area. The idea is to have the side block stick while the page scrolls down until the next block appears and pushes the block above away and become sticky itself. The html structure is as follows:

<div class="container">
    <div class="row">
        <div class="col-md-4 sticky">
            <h2>Example</h2>
            <p class="page-side-block">...</p>
            <a href="#" class="action-button">...</a>
        </div>
        <div class="col-md-8 col-md-offset-4">
            <p>...</p>
        </div>
    </div>
    ...
    <div class="row">
        <div class="col-md-4 sticky">
            <h2>Example</h2>
            <p class="page-side-block">...</p>
            <a href="#" class="action-button">...</a>
        </div>
        <div class="col-md-8 col-md-offset-4">
            <p>...</p>
        </div>
    </div>
</div>

I've managed to get the first block to stick but I don't really know how to get about fixing the functionality as described above. Any help on the matter would be greatly appreciated.

I'll include the javascript (using mootools) below. I know this won't work with the html that is provided above as I've edited it to show the semantics rather than the actual markup.

window.onscroll = function() {
    var stickyBlock = $('sticky-block');
    if (window.getScroll().y > 235) {
        stickyBlock.setStyles({
            position: 'fixed',
            top: '100px',
            width: "350px"
        });
    } else if (window.getScroll().y < 235) {
       stickyBlock.setStyles({
            position: 'absolute',
            top: 0,
            width: null
       });
    }
}

I know that in the new w3c specs a definition has been made for a position: sticky; property. This would make javascript completely unnecessary but so far browser support for it is horrible as shown here.

Again if anyone could help me out, that would be awesome ;)


Solution

  • A bit late night here, but leave you a suggestion.

    If you capture all positions and listen to scroll you can iterate the initial positions and compare it with scroll and make the element fixed when needed.

    In my example I use .pin() that you can find in MooTools More, just to not re-invent the wheel.

    Example: http://jsfiddle.net/2AZ28/

    MooTools:

    var stickyBlock = $$('.sticky').map(function(st){
        return {
            el: st,
            pos: st.getPosition().y,
            height: st.getHeight()
        };
    });
    window.addEvent('scroll', function(){
        var currentScroll = window.getScroll().y;
        stickyBlock.each(function (st, i) {
            if (st.pos <= currentScroll){
                st.el.pin();
                if (stickyBlock[i + 1] && (stickyBlock[i + 1].pos - st.height <= currentScroll)) st.el.setStyle('top', stickyBlock[i + 1].pos - st.height - currentScroll);
            } else {
                st.el.unpin();
            }
        });
    })
    

    Maybe could be more optimized, but hope this helps in your question.