Sticky sidebar: stick to the bottom when scrolling down, top when scrolling up

I was looking for some time to solve my sticky sidebar problem. I have a concrete idea of ​​how I would like him to act; effectively, I would like it to stick to the bottom when you scroll down, and then, as soon as you scroll through the backup, I would like it to stick to the top, in the movement of the fluid (without jumping). I cannot find an example of what I'm trying to achieve, so I created an image that, I hope, illustrates the clarity of the point:

Sticky sidebar: stick to bottom when scrolling down, top when scrolling up

  • The sidebar is under the heading.
  • When you scroll down, the sidebar stays at the page content level so you can scroll both the sidebar and the content.
  • Go to the bottom of the side panel, the side panel sticks to the bottom of the viewport (most plugins allow only sticking to the top, some that allow you to stick to the bottom do not allow both).
  • Reach the bottom, the sidebar sits above the footer.
  • When you scroll through the backup, the sidebar remains at the content level to view the contents and sidebar again.
  • Rotate the top of the sidebar, the sidebar will snap into the top of the viewport.
  • Bring back the top and the sidebar sits back under the heading.

I hope this is enough. I created jsfiddle to test any plugins / scripts that I have reset for this question: http://jsfiddle.net/jslucas/yr9gV/2/ .

+50
jquery position fixed sidebar sticky
Aug 21 '13 at 13:30
source share
5 answers

+1 to a very nice and illustrative image.

I know this is an old question, but I accidentally found the same question that you posted in forum.jquery.com and one answer there (by @ tucker973) suggested one nice library to do this, and would like to share it here.

He called the sticky set @leafo

Here you have the code for a very simple example that I prepared, and a working demo to see the result.

 /*! * Sticky-kit * A jQuery plugin for making smart sticky elements * * Source: http://leafo.net/sticky-kit/ */ $(function() { $(".sidebar").stick_in_parent({ offset_top: 10 }); }); 
 * { font-size: 10px; color: #333; box-sizing: border-box; } .wrapper, .header, .main, .footer { padding: 10px; position: relative; } .wrapper { border: 1px solid #333; background-color: #f5f5f5; padding: 10px; } .header { background-color: #6289AE; margin-bottom: 10px; height: 100px; } .sidebar { position: absolute; padding: 10px; background-color: #ccc; height: 300px; width: 100px; float: left; } .main { background-color: #ccc; height: 600px; margin-left: 110px; } .footer { background-color: #6289AE; margin-top: 10px; height: 250px; } .top { position: absolute; top: 10px; } .bottom { position: absolute; bottom: 10px; } .clear { clear: both; float: none; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script src="http://leafo.net/sticky-kit/src/jquery.sticky-kit.js"></script> <div class="wrapper"> <div class="header"> <a class="top">header top</a> <a class="bottom">header bottom</a> </div> <div class="content"> <div class="sidebar"> <a class="top">sidebar top</a> <a class="bottom">sidebar bottom</a> </div> <div class="main"> <a class="top">main top</a> <a class="bottom">main bottom</a> </div> <div class="clear"></div> </div> <div class="footer"> <a class="top">footer top</a> <a class="bottom">footer bottom</a> </div> </div> 

Of course, all loans go to the creator of the plugin, I just made this example to show it here. I need to perform the same result as you, and found this plugin very useful.

+14
Dec 05 '14 at 12:45
source share

Thanks for the great graphics. I was also looking for a solution to this problem!

Unfortunately, the other answer posted here does not address requirement No. 5, which provides for the ability to scroll backward through the sidebar smoothly.

I created a fiddle that implements all the requirements: http://jsfiddle.net/bN4qu/5/

The basic logic to be implemented:

 If scrolling up OR the element is shorter than viewport Then Set top of element to top of viewport If scrolled above top of element If scrolling down then Set bottom of element at bottom of viewport If scrolled past bottom of element 

In the script, I use CSS3 transform to move the target element around, so it will not work, for example. IE <9. Logic sounds, however, to use a different approach.

In addition, I changed your violin so that the sticky sidebar had a gradient background. This helps show that proper behavior is being manifested.

I hope this is useful to someone!

+10
Jul 29 '14 at 9:43 on
source share

Here is an example of how to implement this:

JavaScript:

 $(function() { var $window = $(window); var lastScrollTop = $window.scrollTop(); var wasScrollingDown = true; var $sidebar = $("#sidebar"); if ($sidebar.length > 0) { var initialSidebarTop = $sidebar.position().top; $window.scroll(function(event) { var windowHeight = $window.height(); var sidebarHeight = $sidebar.outerHeight(); var scrollTop = $window.scrollTop(); var scrollBottom = scrollTop + windowHeight; var sidebarTop = $sidebar.position().top; var sidebarBottom = sidebarTop + sidebarHeight; var heightDelta = Math.abs(windowHeight - sidebarHeight); var scrollDelta = lastScrollTop - scrollTop; var isScrollingDown = (scrollTop > lastScrollTop); var isWindowLarger = (windowHeight > sidebarHeight); if ((isWindowLarger && scrollTop > initialSidebarTop) || (!isWindowLarger && scrollTop > initialSidebarTop + heightDelta)) { $sidebar.addClass('fixed'); } else if (!isScrollingDown && scrollTop <= initialSidebarTop) { $sidebar.removeClass('fixed'); } var dragBottomDown = (sidebarBottom <= scrollBottom && isScrollingDown); var dragTopUp = (sidebarTop >= scrollTop && !isScrollingDown); if (dragBottomDown) { if (isWindowLarger) { $sidebar.css('top', 0); } else { $sidebar.css('top', -heightDelta); } } else if (dragTopUp) { $sidebar.css('top', 0); } else if ($sidebar.hasClass('fixed')) { var currentTop = parseInt($sidebar.css('top'), 10); var minTop = -heightDelta; var scrolledTop = currentTop + scrollDelta; var isPageAtBottom = (scrollTop + windowHeight >= $(document).height()); var newTop = (isPageAtBottom) ? minTop : scrolledTop; $sidebar.css('top', newTop); } lastScrollTop = scrollTop; wasScrollingDown = isScrollingDown; }); } }); 

CSS

 #sidebar { width: 180px; padding: 10px; background: red; float: right; } .fixed { position: fixed; right: 50%; margin-right: -50%; } 

Demo: http://jsfiddle.net/ryanmaxwell/25QaE/

This works as expected in all scenarios and is well supported in IE.

+6
Oct 30 '14 at 19:57
source share
 function fixMe(id) { var e = $(id); var lastScrollTop = 0; var firstOffset = e.offset().top; var lastA = e.offset().top; var isFixed = false; $(window).scroll(function(event){ if (isFixed) { return; } var a = e.offset().top; var b = e.height(); var c = $(window).height(); var d = $(window).scrollTop(); if (b <= c - a) { e.css({position: "fixed"}); isFixed = true; return; } if (d > lastScrollTop){ // scroll down if (e.css("position") != "fixed" && c + d >= a + b) { e.css({position: "fixed", bottom: 0, top: "auto"}); } if (a - d >= firstOffset) { e.css({position: "absolute", bottom: "auto", top: lastA}); } } else { // scroll up if (a - d >= firstOffset) { if (e.css("position") != "fixed") { e.css({position: "fixed", bottom: "auto", top: firstOffset}); } } else { if (e.css("position") != "absolute") { e.css({position: "absolute", bottom: "auto", top: lastA}); } } } lastScrollTop = d; lastA = a; }); } fixMe("#stick"); 

Working example: https://jsfiddle.net/L7xoopst/6/

+1
Sep 21 '15 at 0:11
source share

I was looking for the same thing. Apparently, I needed to look for some obscure conditions to find a similar question with graphics. It turns out exactly what I was looking for. I could not find any plugins, so I decided to do it myself. I hope someone sees this and improves it.

Here is a quick and dirty html sample that I use.

 <div id="main"> <div class="col-1"> </div> <div class="col-2"> <div class="side-wrapper"> sidebar content </div> </div> </div> 

Here jQuery I did:

 var lastScrollPos = $(window).scrollTop(); var originalPos = $('.side-wrapper').offset().top; if ($('.col-2').css('float') != 'none') { $(window).scroll(function(){ var rectbtfadPos = $('.rectbtfad').offset().top + $('.rectbtfad').height(); // scroll up direction if ( lastScrollPos > $(window).scrollTop() ) { // unstick if scrolling the opposite direction so content will scroll with user if ($('.side-wrapper').css('position') == 'fixed') { $('.side-wrapper').css({ 'position': 'absolute', 'top': $('.side-wrapper').offset().top + 'px', 'bottom': 'auto' }); } // if has reached the original position, return to relative positioning if ( ($(window).scrollTop() + $('#masthead').height()) < originalPos ) { $('.side-wrapper').css({ 'position': 'relative', 'top': 'auto', 'bottom': 'auto' }); } // sticky to top if scroll past top of sidebar else if ( ($(window).scrollTop() + $('#masthead').height()) < $('.side-wrapper').offset().top && $('.side-wrapper').css('position') == 'absolute' ) { $('.side-wrapper').css({ 'position': 'fixed', 'top': 15 + $('#masthead').height() + 'px', // padding to compensate for sticky header 'bottom': 'auto' }); } } // scroll down else { // unstick if scrolling the opposite direction so content will scroll with user if ($('.side-wrapper').css('position') == 'fixed') { $('.side-wrapper').css({ 'position': 'absolute', 'top': $('.side-wrapper').offset().top + 'px', 'bottom': 'auto' }); } // check if rectbtfad (bottom most element) has reached the bottom if ( ($(window).scrollTop() + $(window).height()) > rectbtfadPos && $('.side-wrapper').css('position') != 'fixed' ) { $('.side-wrapper').css({ 'width': $('.col-2').width(), 'position': 'fixed', 'bottom': '0', 'top': 'auto' }); } } // set last scroll position to determine if scrolling up or down lastScrollPos = $(window).scrollTop(); }); } 

Some notes:

  • .rectbtfad is the bottommost element of my sidebar.
  • I use the height of my #masthead because it is a sticky title, so it should compensate for it
  • There is a check for float col-2 there, since I use a responsive design and do not want this activation on smaller screens

If someone can clarify this a bit more, it will be great.

0
Feb 12 '14 at 4:19
source share



All Articles