web-dev-qa-db-fra.com

Comment puis-je faire un div coller en haut de l'écran une fois qu'il a défilé à?

Je voudrais créer un div, qui est situé sous un bloc de contenu mais qui, une fois que la page a été suffisamment défilée pour entrer en contact avec sa limite supérieure, devient fixe et défile avec la page.

282
evanr

Vous pouvez utiliser simplement css, en positionnant votre élément comme corrigé :

.fixedElement {
    background-color: #c0c0c0;
    position:fixed;
    top:0;
    width:100%;
    z-index:100;
}

Edit: Vous devriez avoir l'élément avec position absolue, une fois que le décalage de défilement a atteint l'élément, il devrait être changé en fixe, et la position supérieure devrait être mis à zéro.

Vous pouvez détecter le décalage de défilement supérieur du document avec la fonction scrollTop :

$(window).scroll(function(e){ 
  var $el = $('.fixedElement'); 
  var isPositionFixed = ($el.css('position') == 'fixed');
  if ($(this).scrollTop() > 200 && !isPositionFixed){ 
    $el.css({'position': 'fixed', 'top': '0px'}); 
  }
  if ($(this).scrollTop() < 200 && isPositionFixed){
    $el.css({'position': 'static', 'top': '0px'}); 
  } 
});

Lorsque le décalage de défilement atteint 200, l'élément se colle en haut de la fenêtre du navigateur, car il est placé comme étant fixe.

239
CMS

Vous avez vu cet exemple sur la page numéro de Google Code et (récemment seulement) sur la page d'édition de Stack Overflow.

La réponse de CMS ne renverse pas le positionnement lorsque vous faites défiler vers le haut. Voici le code volé sans vergogne de Stack Overflow:

function moveScroller() {
    var $anchor = $("#scroller-anchor");
    var $scroller = $('#scroller');

    var move = function() {
        var st = $(window).scrollTop();
        var ot = $anchor.offset().top;
        if(st > ot) {
            $scroller.css({
                position: "fixed",
                top: "0px"
            });
        } else {
            $scroller.css({
                position: "relative",
                top: ""
            });
        }
    };
    $(window).scroll(move);
    move();
}
<div id="sidebar" style="width:270px;"> 
  <div id="scroller-anchor"></div> 
  <div id="scroller" style="margin-top:10px; width:270px"> 
    Scroller Scroller Scroller
  </div>
</div>

<script type="text/javascript"> 
  $(function() {
    moveScroller();
  });
</script> 

Et un simple démo en direct .

Une alternative naissante et sans script est position: sticky, prise en charge par Chrome, Firefox et Safari. Voir les article sur HTML5Rocks et démo , et documents Mozilla .

238
Josh Lee

À compter de janvier 2017 et de la sortie de Chrome 56, la plupart des navigateurs couramment utilisés prennent en charge la propriété position: sticky en CSS.

#thing_to_stick {
  position: sticky;
  top: 0px;
}

fait le tour pour moi dans Firefox et Chrome.

Dans Safari, vous devez toujours utiliser position: -webkit-sticky.

Les Polyfill sont disponibles pour Internet Explorer et Edge. https://github.com/wilddeer/stickyfill semble être un bon.

45
Colin 't Hart

J'ai eu le même problème que vous et j'ai fini par créer un plugin jQuery pour en prendre soin. En fait, il résout tous les problèmes énumérés ici, en plus d'ajouter quelques fonctionnalités optionnelles.

Les options

stickyPanelSettings = {
    // Use this to set the top margin of the detached panel.
    topPadding: 0,

    // This class is applied when the panel detaches.
    afterDetachCSSClass: "",

    // When set to true the space where the panel was is kept open.
    savePanelSpace: false,

    // Event fires when panel is detached
    // function(detachedPanel, panelSpacer){....}
    onDetached: null,

    // Event fires when panel is reattached
    // function(detachedPanel){....}
    onReAttached: null,

    // Set this using any valid jquery selector to 
    // set the parent of the sticky panel.
    // If set to null then the window object will be used.
    parentSelector: null
};

https://github.com/donnyv/sticky-panel

démo: http://htmlpreview.github.io/?https://github.com/donnyv/sticky-panel/blob /master/jquery.stickyPanel/Main.htm

33
Donny V.

Et voici comment sans jquery (UPDATE: voir d'autres réponses où vous pouvez maintenant le faire avec CSS uniquement)

var startProductBarPos=-1;
window.onscroll=function(){
  var bar = document.getElementById('nav');
  if(startProductBarPos<0)startProductBarPos=findPosY(bar);

  if(pageYOffset>startProductBarPos){
    bar.style.position='fixed';
    bar.style.top=0;
  }else{
    bar.style.position='relative';
  }

};

function findPosY(obj) {
  var curtop = 0;
  if (typeof (obj.offsetParent) != 'undefined' && obj.offsetParent) {
    while (obj.offsetParent) {
      curtop += obj.offsetTop;
      obj = obj.offsetParent;
    }
    curtop += obj.offsetTop;
  }
  else if (obj.y)
    curtop += obj.y;
  return curtop;
}
* {margin:0;padding:0;}
.nav {
  border: 1px red dashed;
  background: #00ffff;
  text-align:center;
  padding: 21px 0;

  margin: 0 auto;
  z-index:10; 
  width:100%;
  left:0;
  right:0;
}

.header {
  text-align:center;
  padding: 65px 0;
  border: 1px red dashed;
}

.content {
  padding: 500px 0;
  text-align:center;
  border: 1px red dashed;
}
.footer {
  padding: 100px 0;
  text-align:center;
  background: #777;
  border: 1px red dashed;
}
<header class="header">This is a Header</header>
<div id="nav" class="nav">Main Navigation</div>
<div class="content">Hello World!</div>
<footer class="footer">This is a Footer</footer>
22
Jim W

Voici comment je l'ai fait avec jQuery. Tout cela était concocté à partir de diverses réponses sur le débordement de pile. Cette solution met en cache les sélecteurs pour des performances plus rapides et résout également le problème du "saut" lorsque le div collant devient collant.

Découvrez-le sur jsfiddle: http://jsfiddle.net/HQS8s/

CSS:

.stick {
    position: fixed;
    top: 0;
}

JS:

$(document).ready(function() {
    // Cache selectors for faster performance.
    var $window = $(window),
        $mainMenuBar = $('#mainMenuBar'),
        $mainMenuBarAnchor = $('#mainMenuBarAnchor');

    // Run this on scroll events.
    $window.scroll(function() {
        var window_top = $window.scrollTop();
        var div_top = $mainMenuBarAnchor.offset().top;
        if (window_top > div_top) {
            // Make the div sticky.
            $mainMenuBar.addClass('stick');
            $mainMenuBarAnchor.height($mainMenuBar.height());
        }
        else {
            // Unstick the div.
            $mainMenuBar.removeClass('stick');
            $mainMenuBarAnchor.height(0);
        }
    });
});
9
JohnB

Voici une autre option:

JAVASCRIPT

var initTopPosition= $('#myElementToStick').offset().top;   
$(window).scroll(function(){
    if($(window).scrollTop() > initTopPosition)
        $('#myElementToStick').css({'position':'fixed','top':'0px'});
    else
        $('#myElementToStick').css({'position':'absolute','top':initTopPosition+'px'});
});

Votre #myElementToStick devrait commencer par la propriété position:absolute CSS.

6
kunde

Comme Josh Lee et Colin 't Hart ont dit, vous pouvez éventuellement simplement utiliser position: sticky; top: 0; pour appliquer à la div que vous voulez que le défilement ...

De plus, la seule chose à faire est de copier ceci dans le haut de votre page ou de le formater pour l’intégrer dans une feuille CSS externe:

<style>
#sticky_div's_name_here { position: sticky; top: 0; }
</style>

Il suffit de remplacer #sticky_div's_name_here par le nom de votre div. Si votre div était <div id="example">, vous mettriez #example { position: sticky; top: 0; }.

2
Max Garner

Voici une version de plus à essayer pour ceux qui ont des problèmes avec les autres. Il rassemble les techniques décrites dans cette question en double , et génère dynamiquement les DIV auxiliaires requises, de sorte qu'aucun code HTML supplémentaire n'est requis.

CSS:

.sticky { position:fixed; top:0; }

JQuery:

function make_sticky(id) {
    var e = $(id);
    var w = $(window);
    $('<div/>').insertBefore(id);
    $('<div/>').hide().css('height',e.outerHeight()).insertAfter(id);
    var n = e.next();
    var p = e.prev();
    function sticky_relocate() {
      var window_top = w.scrollTop();
      var div_top = p.offset().top;
      if (window_top > div_top) {
        e.addClass('sticky');
        n.show();
      } else {
        e.removeClass('sticky');
        n.hide();
      }
    }
    w.scroll(sticky_relocate);
    sticky_relocate();
}

Pour rendre un élément collant, faites:

make_sticky('#sticky-elem-id');

Lorsque l'élément devient collant, le code gère la position du contenu restant pour l'empêcher de sauter dans l'espace laissé par l'élément collant. Il rétablit également l'élément collant dans sa position d'origine non collante lors du défilement arrière.

1
Dan

Voici une version étendue de la réponse de Josh Lee. Si vous souhaitez que la division soit sur la barre latérale à droite et flotte dans une plage (c’est-à-dire, vous devez spécifier les positions d’ancrage supérieure et inférieure). Il corrige également un bogue lorsque vous le visualisez sur des appareils mobiles (vous devez vérifier la position du défilement à gauche sinon le div se déplacera hors de l'écran).

function moveScroller() {
    var move = function() {
        var st = $(window).scrollTop();
        var sl = $(window).scrollLeft();
        var ot = $("#scroller-anchor-top").offset().top;
        var ol = $("#scroller-anchor-top").offset().left;
        var bt = $("#scroller-anchor-bottom").offset().top;
        var s = $("#scroller");
        if(st > ot) {
            if (st < bt - 280) //280px is the approx. height for the sticky div
            {
                s.css({
                    position: "fixed",
                    top: "0px",
                    left: ol-sl
                }); 
            }
            else
            {
                s.css({
                    position: "fixed",
                    top: bt-st-280,
                    left: ol-sl
                }); 
            }
        } else {
            s.css({
                position: "relative",
                top: "",
                left: ""
            });

        }
    };
    $(window).scroll(move);
    move();
}
1
realwecan

Je suis tombé sur cela en cherchant la même chose. Je sais que c'est une vieille question mais je pensais offrir une réponse plus récente.

Scrollorama a une fonction "épingler" qui correspond exactement à ce que je cherchais.

http://johnpolacek.github.io/scrollorama/

1
pbryd

Ma solution est un peu détaillée, mais elle gère le positionnement variable à partir du bord gauche pour les présentations centrées.

// Ensurs that a element (usually a div) stays on the screen
//   aElementToStick   = The jQuery selector for the element to keep visible
global.makeSticky = function (aElementToStick) {
    var $elementToStick = $(aElementToStick);
    var top = $elementToStick.offset().top;
    var origPosition = $elementToStick.css('position');

    function positionFloater(a$Win) {
        // Set the original position to allow the browser to adjust the horizontal position
        $elementToStick.css('position', origPosition);

        // Test how far down the page is scrolled
        var scrollTop = a$Win.scrollTop();
        // If the page is scrolled passed the top of the element make it stick to the top of the screen
        if (top < scrollTop) {
            // Get the horizontal position
            var left = $elementToStick.offset().left;
            // Set the positioning as fixed to hold it's position
            $elementToStick.css('position', 'fixed');
            // Reuse the horizontal positioning
            $elementToStick.css('left', left);
            // Hold the element at the top of the screen
            $elementToStick.css('top', 0);
        }
    }

    // Perform initial positioning
    positionFloater($(window));

    // Reposition when the window resizes
    $(window).resize(function (e) {
        positionFloater($(this));
    });

    // Reposition when the window scrolls
    $(window).scroll(function (e) {
        positionFloater($(this));
    });
};
1
Josh Russo

La réponse acceptée fonctionne mais ne revient pas à la position précédente si vous la faites défiler au-dessus. Il est toujours collé au sommet après y avoir été placé.

  $(window).scroll(function(e) {
    $el = $('.fixedElement');
    if ($(this).scrollTop() > 42 && $el.css('position') != 'fixed') {
      $('.fixedElement').css( 'position': 'fixed', 'top': '0px');

    } else if ($(this).scrollTop() < 42 && $el.css('position') != 'relative') {
      $('.fixedElement').css( 'relative': 'fixed', 'top': '42px');
//this was just my previous position/formating
    }
  });

la réponse de Jleedev a fonctionné, mais je n'ai pas réussi à la faire fonctionner. Sa page d'exemple n'a pas non plus fonctionné (pour moi).

0
Forge

J'ai utilisé une partie du travail ci-dessus pour créer cette technologie. Je l'ai un peu amélioré et j'ai pensé partager mon travail. J'espère que cela t'aides.

Code jsfuddle

function scrollErrorMessageToTop() {
    var flash_error = jQuery('#flash_error');
    var flash_position = flash_error.position();

    function lockErrorMessageToTop() {
        var place_holder = jQuery("#place_holder");
        if (jQuery(this).scrollTop() > flash_position.top && flash_error.attr("position") != "fixed") {
            flash_error.css({
                'position': 'fixed',
                'top': "0px",
                "width": flash_error.width(),
                "z-index": "1"
            });
            place_holder.css("display", "");
        } else {
            flash_error.css('position', '');
            place_holder.css("display", "none");
        }

    }
    if (flash_error.length > 0) {
        lockErrorMessageToTop();

        jQuery("#flash_error").after(jQuery("<div id='place_holder'>"));
        var place_holder = jQuery("#place_holder");
        place_holder.css({
            "height": flash_error.height(),
            "display": "none"
        });
        jQuery(window).scroll(function(e) {
            lockErrorMessageToTop();
        });
    }
}
scrollErrorMessageToTop();​

C'est un peu plus dynamique d'une manière de faire le parchemin. Il faut un peu de travail et à un moment donné, je vais en faire un problème, mais c’est ce que j’ai trouvé après une heure de travail.

0
brand-it

Vous pouvez ajouter 3 lignes supplémentaires pour que, lorsque l'utilisateur revient au début de la liste, la div reste à son emplacement d'origine:

Voici le code:

if ($(this).scrollTop() < 200 && $el.css('position') == 'fixed'){
    $('.fixedElement').css({'position': 'relative', 'top': '200px'});
}
0
Alex Rashkov

Pas une solution exacte mais une excellente alternative à considérer

this barre de défilement CSS uniquement en haut de l'écran. Résolu tout le problème avec UNIQUEMENT CSS , NON JavaScript, NON JQuery, Non Travail du cerveau ( lol ).

Profitez de mon violon : D tous les codes sont inclus ici :)

CSS

#menu {
position: fixed;
height: 60px;
width: 100%;
top: 0;
left: 0;
border-top: 5px solid #a1cb2f;
background: #fff;
-moz-box-shadow: 0 2px 3px 0px rgba(0, 0, 0, 0.16);
-webkit-box-shadow: 0 2px 3px 0px rgba(0, 0, 0, 0.16);
box-shadow: 0 2px 3px 0px rgba(0, 0, 0, 0.16);
z-index: 999999;
}

.w {
    width: 900px;
    margin: 0 auto;
    margin-bottom: 40px;
}<br type="_moz">

Mettez le contenu assez longtemps pour que vous puissiez voir l'effet ici :) Oh, et la référence est aussi là, pour le fait qu'il mérite son crédit

CSS SEULEMENT en haut de la barre de défilement de l'écran

0
weia design

Voici un exemple utilisant le plugin jquery-visible: http://jsfiddle.net/711p4em4/ .

HTML:

<div class = "wrapper">
    <header>Header</header>
    <main>
        <nav>Stick to top</nav>
        Content
    </main>
    <footer>Footer</footer>
</div>

CSS:

* {
    margin: 0;
    padding: 0;
}

body {
    background-color: #e2e2e2;
}

.wrapper > header,
.wrapper > footer {
    font: 20px/2 Sans-Serif;
    text-align: center;
    background-color: #0040FF;
    color: #fff;
}

.wrapper > main {
    position: relative;
    height: 500px;
    background-color: #5e5e5e;
    font: 20px/500px Sans-Serif;
    color: #fff;
    text-align: center;
    padding-top: 40px;
}

.wrapper > main > nav {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    font: 20px/2 Sans-Serif;
    color: #fff;
    text-align: center;
    background-color: #FFBF00;
}

.wrapper > main > nav.fixed {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
}

JS (inclure le plugin jquery-visible):

(function($){

    /**
     * Copyright 2012, Digital Fusion
     * Licensed under the MIT license.
     * http://teamdf.com/jquery-plugins/license/
     *
     * @author Sam Sehnert
     * @desc A small plugin that checks whether elements are within
     *       the user visible viewport of a web browser.
     *       only accounts for vertical position, not horizontal.
     */
    var $w = $(window);
    $.fn.visible = function(partial,hidden,direction){

        if (this.length < 1)
            return;

        var $t        = this.length > 1 ? this.eq(0) : this,
            t         = $t.get(0),
            vpWidth   = $w.width(),
            vpHeight  = $w.height(),
            direction = (direction) ? direction : 'both',
            clientSize = hidden === true ? t.offsetWidth * t.offsetHeight : true;

        if (typeof t.getBoundingClientRect === 'function'){

            // Use this native browser method, if available.
            var rec = t.getBoundingClientRect(),
                tViz = rec.top    >= 0 && rec.top    <  vpHeight,
                bViz = rec.bottom >  0 && rec.bottom <= vpHeight,
                lViz = rec.left   >= 0 && rec.left   <  vpWidth,
                rViz = rec.right  >  0 && rec.right  <= vpWidth,
                vVisible   = partial ? tViz || bViz : tViz && bViz,
                hVisible   = partial ? lViz || rViz : lViz && rViz;

            if(direction === 'both')
                return clientSize && vVisible && hVisible;
            else if(direction === 'vertical')
                return clientSize && vVisible;
            else if(direction === 'horizontal')
                return clientSize && hVisible;
        } else {

            var viewTop         = $w.scrollTop(),
                viewBottom      = viewTop + vpHeight,
                viewLeft        = $w.scrollLeft(),
                viewRight       = viewLeft + vpWidth,
                offset          = $t.offset(),
                _top            = offset.top,
                _bottom         = _top + $t.height(),
                _left           = offset.left,
                _right          = _left + $t.width(),
                compareTop      = partial === true ? _bottom : _top,
                compareBottom   = partial === true ? _top : _bottom,
                compareLeft     = partial === true ? _right : _left,
                compareRight    = partial === true ? _left : _right;

            if(direction === 'both')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop)) && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
            else if(direction === 'vertical')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop));
            else if(direction === 'horizontal')
                return !!clientSize && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
        }
    };

})(jQuery);

$(function() {
    $(window).scroll(function() {
        $(".wrapper > header").visible(true) ?
            $(".wrapper > main > nav").removeClass("fixed") :
            $(".wrapper > main > nav").addClass("fixed");
    });
});
0
DRD

Les informations fournies pour répondre à cette autre question peuvent vous aider, Evan:

Vérifier si l'élément est visible après le défilement

En gros, vous souhaitez modifier le style de l'élément pour le définir comme étant corrigé uniquement après avoir vérifié que la valeur document.body.scrollTop est égale ou supérieure au haut de votre élément.

0
Amber

En javascript, vous pouvez faire:

var element = document.getElementById("myid");
element.style.position = "fixed";
element.style.top = "0%";
0
htmlfarmer

J'ai des liens mis en place dans un div donc c'est une liste verticale de liens de lettre et de nombre.

#links {
    float:left;
    font-size:9pt;
    margin-left:0.5em;
    margin-right:1em;
    position:fixed;
    text-align:center;
    width:0.8em;
}

J'ai ensuite configuré cette fonction pratique jQuery pour enregistrer la position chargée, puis changer la position en position fixe lors du défilement au-delà de cette position.

NOTE: cela ne fonctionne que si les liens sont visibles lors du chargement de la page !!

var listposition=false;
jQuery(function(){
     try{
        ///// stick the list links to top of page when scrolling
        listposition = jQuery('#links').css({'position': 'static', 'top': '0px'}).position();
        console.log(listposition);
        $(window).scroll(function(e){
            $top = $(this).scrollTop();
            $el = jQuery('#links');
            //if(typeof(console)!='undefined'){
            //    console.log(listposition.top,$top);
            //}
            if ($top > listposition.top && $el.css('position') != 'fixed'){
                $el.css({'position': 'fixed', 'top': '0px'});
            }
            else if ($top < listposition.top && $el.css('position') == 'fixed'){
                $el.css({'position': 'static'});
            }
        });

    } catch(e) {
        alert('Please vendor [email protected] (Myvendor JavaScript Issue)');
    }
});
0
Artistan