web-dev-qa-db-fra.com

Barre latérale collante: coller en bas lors du défilement vers le bas, en haut lors du défilement vers le haut

Je cherche depuis un certain temps maintenant une solution à mon problème de barre latérale collante. J'ai une idée précise de la façon dont j'aimerais qu'elle agisse; en effet, je voudrais qu'il colle au bas lorsque vous faites défiler vers le bas, puis dès que vous faites défiler vers le haut, je voudrais qu'il colle au sommet, dans un mouvement fluide (pas de saut). Je ne suis pas en mesure de trouver un exemple de ce que j'essaie de réaliser, j'ai donc créé une image qui, je l'espère, illustrera le point plus clairement:

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

  1. La barre latérale se trouve sous l'en-tête.
  2. Lorsque vous faites défiler vers le bas, la barre latérale reste au niveau du contenu de la page afin que vous puissiez faire défiler la barre latérale et le contenu.
  3. Atteignez le bas de la barre latérale, la barre latérale colle au bas de la fenêtre d'affichage (la plupart des plugins ne permettent que de coller en haut, certains qui permettent de coller en bas ne permettent pas les deux).
  4. Atteignez le bas, la barre latérale se trouve au-dessus du pied de page.
  5. Lorsque vous faites défiler vers le haut, la barre latérale reste au niveau du contenu afin que vous puissiez à nouveau faire défiler le contenu et la barre latérale.
  6. Atteignez le haut de la barre latérale, la barre latérale reste en haut de la fenêtre.
  7. Atteignez le haut et la barre latérale se place en dessous de l'en-tête.

J'espère que c'est assez d'informations. J'ai créé un jsfiddle pour tester tous les plugins/scripts, que j'ai réinitialisé pour cette question: http://jsfiddle.net/jslucas/yr9gV/2/.

71
andbamnan

+ 1 à l'image très agréable et illustrative.

Je sais que c'est une vieille question, mais j'ai trouvé nonchalamment la même question postée par vous dans forum.jquery.com et une réponse là-bas (par @ tucker973), a suggéré une belle bibliothèque pour faire cela et a voulu la partager ici.

Il s'appelle sticky-kit par @ leafo

Ici vous avez le code d'un exemple très basique que j'ai préparé et une démo de travail pour voir le résultat.

/*!
 * 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>

Bien sûr, tous les crédits vont au créateur du plugin, je n'ai fait que cet exemple pour le montrer ici. J'ai besoin d'obtenir le même résultat que vous recherchiez et j'ai trouvé ce plugin très utile.

20
gmo

Merci pour le super graphique. Je cherchais également une solution à ce défi!

Malheureusement, l'autre réponse publiée ici ne répond pas à l'exigence n ° 5 qui stipule la possibilité de faire défiler la barre latérale en douceur.

J'ai créé un violon qui implémente toutes les exigences: http://jsfiddle.net/bN4qu/5/

La logique de base qui doit être mise en œuvre est:

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

Dans le violon, j'utilise la transformation CSS3 pour déplacer l'élément cible, donc cela ne fonctionnera pas, par exemple. IE <9. La logique est cependant bonne pour utiliser une approche différente.

De plus, j'ai modifié votre violon pour que la barre latérale collante ait un fond dégradé. Cela permet de montrer que le bon comportement est affiché.

J'espère que cela sera utile à quelqu'un!

10
Travis Kriplean

Voici un exemple de mise en œuvre de ceci:

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%;
}

Démo: http://jsfiddle.net/ryanmaxwell/25QaE/

Cela fonctionne comme prévu dans tous les scénarios et est bien pris en charge dans IE aussi.

8
Anoop Naik
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");

Exemple de travail: https://jsfiddle.net/L7xoopst/6/

1
SezginOnline

Il y a un plugin relativement inconnu dans le référentiel Wordpress connu sous le nom WP Sticky Sidebar. Le plugin fait exactement ce que vous vouliez (Sticky sidebar: coller de bas en bas lors du défilement vers le bas) , en haut lors du défilement vers le haut) WP Sticky Sidebar Wordpress Lien vers le référentiel: https://wordpress.org/plugins/mystickysidebar/

1
Manju Talluri

Je cherchais exactement la même chose. Apparemment, j'avais besoin de rechercher des termes obscurs juste pour trouver une question similaire avec le graphique. Il s'avère que c'est exactement ce que je cherchais. Je n'ai trouvé aucun plugin, j'ai donc décidé de le faire moi-même. J'espère que quelqu'un le verra et l'affinera.

Voici un exemple html rapide et sale que j'utilise.

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

Voici la jQuery que j'ai faite:

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();

    });
}

Quelques notes:

  • .rectbtfad est l'élément le plus bas de ma barre latérale
  • J'utilise la hauteur de mon #masthead car c'est un en-tête collant donc il doit le compenser
  • Il y a une vérification pour le flotteur col-2 car j'utilise un design réactif et je ne veux pas que cela s'active sur des écrans plus petits

Si quelqu'un peut affiner un peu plus ce serait génial.

0
callmeforsox