Bonjour,
je vous explique ce que je veux faire :
j'ai un système d'accordéon Bootstrap qui contient 3 colonnes
La troisième doit suivre le scroll et rester en position fixed dans la hauteur du body de mon premier accordéon
En faite la colonne 3 se bloque en haut de mon accordéon et doit rester bloqué en bas de mon panel-body quand on scroll.

J'utilise un plugin : jquery.sticky.js
il fonctionne très bien pour fixer la colonne 3 au scroll, mais ne reste pas bloqué en bas dans le corps de mon accordéon.

je ne sais pas si j'ai été clair mais j'ai besoin d'aide.

merci

16 réponses


je crois t'avoir répondu dans la section javascript....
avec un semblant de la réponse de JeremieMeunier ;)

bonjour,

j'ai suivi le tuto de Grafikart pour le menu collant, ça fonctionne mais évidement j'ai un petit soucis.
je vous mets le code html et JS.

<div class="container">
    <div class="row">
    <div class="title">
    <h1>Voici un titre</h1>
    </div>
    <div class="col-lg-12">
        <div class="col-lg-8">
            <div class="content">
                <p>

        The goal of a reset stylesheet is to reduce browser inconsistencies in things like default line heights, margins and font sizes of headings, and so on. The general reasoning behind this was discussed in a May 2007 post, if you're interested. Reset styles quite often appear in CSS frameworks, and the original "meyerweb reset" found its way into Blueprint, among others.

        The reset styles given here are intentionally very generic. There isn't any default color or background set for the body element, for example. I don't particularly recommend that you just use this in its unaltered state in your own projects. It should be tweaked, edited, extended, and otherwise tuned to match your specific reset baseline. Fill in your preferred colors for the page, links, and so on.

        In other words, this is a starting point, not a self-contained black box of no-touchiness.

        If you want to use my reset styles, then feel free! It's all explicitly in the public domain (I have to formally say that or else people ask me about licensing). You can grab a copy of the file to use and tweak as fits you best. If you're more of the copy-and-paste type, or just want an in-page preview of what you'll be getting, here it is. </p>
            </div>
        </div>
        <div class="col-lg-4 risk">
        <div class="sidebar">
            <div class="niveauRisk" data-sticky data-offset="40" data-constraint=".sidebar">
              <p>Niveaux de gestion du risque</p>
            <div class="risque">
                   <ul>
                    <li><a href="#" data-toggle="modal" data-target="#modalRegister"><img src="img/dot-rouge.png">A traiter</a></li>
                    <li><a href="#" data-toggle="modal" data-target="#modalRegister"><img src="img/dot-orange.png">A Gérer</a></li>
                    <li><a href="#" data-toggle="modal" data-target="#modalRegister"><img src="img/dot-bleu.png">A surveiller</a></li>
                   </ul>
                 </div>
            </div>
        </div>
        </div>
    </div>
    </div>
</div>

Le JS :

(function(){

    var scrollY = function(){
        var supportPageOffset = window.pageXOffset !== undefined;
        var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
        return supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
    }

    var elements = document.querySelectorAll('[data-sticky]')
    for (var i = 0; i < elements.length; i++) {
        (function(element){
            var rect = element.getBoundingClientRect()
            var offset = parseInt(element.getAttribute('data-offset') || 0, 10)
            if(element.getAttribute('data-constraint')){
                var constraint = document.querySelector(element.getAttribute('data-constraint'))
            } else{
                var constraint = document.body
            }
            var constraintRect = constraint.getBoundingClientRect()
            var constraintBottom = constraintRect.top + scrollY() + constraintRect.height - offset - rect.height
            var top = rect.top + scrollY()

            var onScroll = function () {
            if (scrollY() > constraintBottom && element.style.position != 'absolute'){
                element.style.position = 'absolute'
                element.style.bottom = '0'
                element.style.top = 'auto'
            } else if (scrollY() > top - offset && scrollY() < constraintBottom && element.style.position != 'fixed') {
                element.classList.add('fixed')
                element.style.bottom = 'auto'
                element.style.top = offset + "px"
                element.style.bottom = 'auto'
            } else if(scrollY() < top - offset && element.style.position != 'static'){
                element.classList.remove('fixed')
                element.style.position = 'static'
            }
            }

                    window.addEventListener('scroll', onScroll)

        })(elements[i])

    };

})()

Mon soucis manque de fluidité, et ça passe du top au bottom directement.
Je n'ai pas utilisé entièrement le code de Grafikart je l'ai adapté à mes besoin sachant que je l'utilise que pour la side bar.

merci

il manque le 'fake' non ?
du coup quand ta div "niveauRisk" passe en sticky "sidebar" se 'vide' et "niveauRisk" se retrouve en bottom 0;
c koi le css de "sidebar" ?

simple :

.sidebar{
    height: 300px;
    border: 1px solid #000;
    padding: 10px;
}

j'utilise bootstrap je sais pas si ça à une influence

mais le fake est utilisé uniquement pour le menu du haut et le resize non ?

ajoute lui un position : relative, pour voir...

'fake' ou 'push' c pour éviter l'espace vide que va créer ton élément en passant à absolute...

je vais tester je te tiens au courant merci

bonsoir
Bon j'ai testé mai c'est sacadé je ne comprends pas...

bsr,
ça fonctionne ?
saccadé ? ça veut dire que ta div saute ?
tu as un exemple en ligne ?

saccadé oui on dirait que la div saute d'une position top à une position de tant de px.
non je n'ai pas d'exemple en ligne je travail en local

ce ne serait pas de 40px ?
essaie d'enlever data-offset="40" de niveauRisk

un article qui devrait t'intéresser :
position sticky & polyfills

comme t'as qu'un seul sticky, tu peux faire un truc plus simple en virant la boucle et l'offset :
et gérer le changement de style avec des règles css
exemple :
html :

<div class="container">
    <div class="constraint">
        <div class="monSticky" data-constraint=".constraint"></div>
        <p>paragraphe pousse par le fake. si y'en a pas, à toi de voir</p>
    </div>
</div>

js :

var sticky = document.querySelector('.monSticky');
var stickyRect = sticky.getBoundingClientRect();
    // on dimensionne car on va perdre le rect en fixed et absolute
    sticky.style.width = stickyRect.width + 'px';
    sticky.style.height = stickyRect.height + 'px';

var constraint = (sticky.dataset.constraint)?document.querySelector(sticky.dataset.constraint):document.body;
var constraintRect = constraint.getBoundingClientRect();

// si t'as qqc après ton sticky
var fake = document.createElement('div');
    fake.style.width = stickyRect.width + 'px';
    fake.style.height = stickyRect.height + 'px';

var onScroll = function() {
    // tu peux garder le poly scrollY à la place de pageYOffset
    if (window.pageYOffset >= stickyRect.top){
        // si ça sort du constraint
        if(window.pageYOffset + stickyRect.height > constraintRect.bottom && !sticky.classList.contains('stickyBottom')) {
            sticky.classList.remove('sticky');
            sticky.classList.add('stickyBottom');
        }
        // mode sticky
        else if (window.pageYOffset + stickyRect.height < constraintRect.bottom && !sticky.classList.contains('sticky')) {
            sticky.classList.add('sticky');
            sticky.classList.remove('stickyBottom');
           // si t'as qqc après ton sticky
            sticky.parentNode.insertBefore(fake, sticky);
    }
    // pos de base
    }else if ((sticky.classList.contains('sticky') || sticky.classList.contains('stickyBottom'))) {
        sticky.classList.remove('sticky');
        sticky.classList.remove('stickyBottom');
        // si t'as qqc après ton sticky
        sticky.parentNode.removeChild(fake);
    }
};

window.addEventListener('scroll', onScroll);

et le css :

.container{height:2000px;}
.constraint{height:600px; border:1px solid #000;position:relative;top:100px;width:50%;margin:auto;}
.monSticky{min-height:200px;background:tomato;}

/* je trouve mieux de définir des règles css
car si monSticky à une position différente de static y'aura pas écrasement */
.sticky{top:0; position:fixed;}
.stickyBottom{position:absolute;bottom:0; top:auto;}

ça ne gère pas le resize, donc si tu resize ou reload avec un scroll>0, ça risque de bugguer...
mais tu l'avais pas mis donc .... :) perso je le rajouterais... comme le fake
sinon, g testé, c fluide...

merci je vais regarder ça.