¿Cómo puedo hacer que un div se pegue en la parte superior de la pantalla una vez que se ha desplazado?

305

Me gustaría crear un div, que se encuentra debajo de un bloque de contenido, pero que una vez que la página se ha desplazado lo suficiente como para contactar con su límite superior, se fija en su lugar y se desplaza con la página.

evanr
fuente
55
A partir de junio de 2014, el complemento jQuery Sticky-kit es una de las opciones más sencillas, ya que proporciona una barrera de entrada extremadamente baja y muchas funciones. Excelente lugar para comenzar si está buscando una manera fácil de despegar rápidamente.
user456584
1
Trucos de CSS: css-tricks.com/scroll-fix-content
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
33
Agregar CSS position: sticky; top:0;funciona en la mayoría de los navegadores en enero de 2017.
Colin 't Hart
99
Santa mierda, esa position: sticky;cosa es mágica.
tscizzle

Respuestas:

260

Puede usar simplemente css, posicionando su elemento como fijo :

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

Editar: debe tener el elemento con posición absoluta, una vez que el desplazamiento de desplazamiento ha alcanzado el elemento, debe cambiarse a fijo, y la posición superior debe establecerse en cero.

Puede detectar el desplazamiento de desplazamiento superior del documento con la función 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'}); 
  } 
});

Cuando el desplazamiento desfase alcanza 200, el elemento se adhieren a la parte superior de la ventana del navegador, ya que se coloca como fijo.

CMS
fuente
44
eso no logra lo que estoy buscando. Me gustaría que el elemento comience a 200 px debajo de la parte superior de la página (para dejar espacio para otro contenido) y luego, una vez que el usuario se haya desplazado hacia abajo, se fijará en la parte superior.
evanr
3
su edición realmente satisface las necesidades de la pregunta ahora, pero aún tiene un problema cuando la página se desplaza hacia arriba nuevamente. después de alcanzar el elemento scrollTop, guárdelo en algún lugar, y cuando la página llegue a esa posición nuevamente (al desplazarse hacia arriba) cambie el CSS de nuevo al valor predeterminado ... probablemente sea mejor hacerlo con un .toggleClass y luego ...
Sander
99
Esto es más o menos lo que ocurre con, pero tuve que eliminar la posición fija cuando la ventana se desplaza hacia arriba. if ($(this).scrollTop() < 200 && $el.css('position') == 'fixed') { $('.fixedElement').css({'position': 'static', 'top': '0px'}); }
Derrick Petzold
1
@DerrickPetzold Puse eso en la respuesta, cosas bastante importantes :)
MarioDS
1
¡el new exampleenlace que diste está tan limpio y claro que ni siquiera puedo verlo! -_-
sohaiby
245

Has visto este ejemplo en la página de problemas de Google Code y (solo recientemente) en la página de edición de Stack Overflow.

La respuesta de CMS no revierte el posicionamiento cuando te desplazas hacia arriba. Aquí está el código descaradamente robado 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> 

Y una simple demostración en vivo .

Una alternativa naciente y libre de scripts es position: sticky, que es compatible con Chrome, Firefox y Safari. Vea el artículo sobre HTML5Rocks y demo , y documentos de Mozilla .

Josh Lee
fuente
3
Por alguna razón, el {scroll: false} me estaba dando problemas (jQuery 1.6.2). Parece trabajar sin ella. Bifurcación de la demostración vinculada. ¿Alguna idea de si sirve para un propósito?
Eddie
Estoy teniendo muchos problemas con esto, por mi vida no puedo replicar, incluso he tratado de replicar la demostración en vivo y no funciona. ¿Alguien puede vincular a un tutorial que proporciona instrucciones paso a paso?
Trevor Dupp
2
Esto parece funcionar bien, cuando uso la misma versión de jQuery que la demostración (1.3.2). En algún momento offsetdebe haber dejado de aceptar un objeto como entrada api.jquery.com/offset . @Eddie Su modificación debe ser segura con jQuery actual.
Graeme
1
¿Hay alguna razón por la que no se podía sustituir var d = $("#scroller-anchor").offset().top;con var d = $("#sidebar").offset().top;y deshacerse del vacío div desplazador-ancla todos juntos? Aquí está mi tenedor demostrando de lo que estoy hablando.
Mike Deck
@MikeDeck Sospecho que si hay márgenes o relleno, le gustaría poder controlar dónde se coloca el desplazador en relación con el contenedor.
Josh Lee
72

A partir de enero de 2017 y el lanzamiento de Chrome 56, la mayoría de los navegadores de uso común admiten la position: stickypropiedad en CSS.

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

hace el truco para mí en Firefox y Chrome.

En Safari todavía necesitas usar position: -webkit-sticky.

Polyfills están disponibles para Internet Explorer y Edge; https://github.com/wilddeer/stickyfill parece ser bueno.

Colin 't Hart
fuente
55
Esto es compatible con la mayoría de los navegadores de uso común en la actualidad. Consulte caniuse.com/#feat=css-sticky. En segundo lugar, prefiero una solución que se puede reducir a 2 líneas de código a una versión que requiera Javascript personalizado. Y también es a prueba de futuro. Use un polyfill si le preocupa la compatibilidad del navegador.
Colin 't Hart
1
No puede ser más fácil que esto :)
comenzó
1
Me gustaría agregar a este comentario que podemos indexar en z: 99999 ;, porque si no es así, el otro contenido se representará primero. Pero esta debería ser la solución aceptada.
dayanrr91
Simplemente envuélvelo en un div con id = "thing_to_stick"
Anton el
Solución simple y fácil. Y funciona mejor que otras soluciones en mi caso, por supuesto.
fsevenm
33

Tuve el mismo problema que tú y terminé haciendo un complemento jQuery para solucionarlo. En realidad, resuelve todos los problemas que la gente ha enumerado aquí, además de agregar algunas características opcionales también.

Opciones

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

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

Donny V.
fuente
1
¡Oye! ¡Gracias! Esta es una gran solución, y gracias por compartir, seguro que me ahorró mucho tiempo. Esta debería ser la solución general aceptada para esta pregunta, ya que, por lo que he leído, es la solución más completa. Básicamente, los otros no resolvieron el problema con la posición X original de un bloque después de la posición: se aplica el estilo fijo. El tuyo resuelve este problema. De verdad, muchas gracias!
Marcos Buarque
Hola Donny, también me encanta tu complemento (v1.4.1) ... encontré un problema, los elementos de bloque perdieron su ancho si no se especificaba ninguno. Entonces lo alteró al separar ... solo configurando el ancho para que permanezca igual. code// separar panel node.css ({"margin": 0, "left": nodeLeft, "top": newNodeTop, "position": "fixed", "width": node.width ()}); code
Will Hancock
Busqué e intenté muchas soluciones, y esto funcionó "desde el primer momento". ¡Increíble trabajo! ¡Gracias!
ajtatum
2
@WillHancock Agregué soporte para iPad, arreglé el error de actualización y agregué los eventos onDetached y onReattached. Los nuevos eventos le darán acceso al panel y al panel espaciador después de que se haya separado y vuelto a conectar.
Donny V.
44
También se agregó una opción parentSelector para admitir divs de desplazamiento.
Donny V.
24

Y así es como sin jquery (ACTUALIZACIÓN: vea otras respuestas donde ahora puede hacer esto solo con CSS)

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>

Jim W dice reinstalar a Mónica
fuente
44
¡Gracias! Es difícil encontrar soluciones nativas de JS en estos días. Esto funcionó perfectamente.
Sherri
Muchas gracias, esto funcionó perfectamente ya que jquery estaba en conflicto con algún código empresarial heredado que tiene mi proyecto
sng
aunque me encuentro con un problema en el que si me desplazo al final de la página, automáticamente volveré a aparecer en la parte superior.
sng
@sng ¿Mi página de muestra hace eso?
Jim W dice que reinstale a Mónica el
@JimW descubrí el problema. Estaba tratando de usarlo con una barra de menú basada en vertical al lado de un div de contenido principal a la izquierda. Estaba fallando cuando te desplazas hacia abajo, ya que no puede determinar cuándo está tocando la parte inferior de la página correctamente. Terminé agregando una línea de código para establecer la altura de
división
9

Así es como lo hice con jquery. Todo esto fue improvisado de varias respuestas en el desbordamiento de la pila. Esta solución almacena en caché los selectores para un rendimiento más rápido y también resuelve el problema de "salto" cuando el div pegajoso se vuelve pegajoso.

Compruébelo en 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);
        }
    });
});
JohnB
fuente
7

Aquí hay otra opción:

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'});
});

Su #myElementToStickdebe comenzar con position:absolutela propiedad CSS.

Kunde
fuente
1
Creo que esta es una solución muy limpia y fácil. Simplemente no posicionaría el elemento "absoluto", esto podría romper el diseño, simplemente lo establecería en estático.
Gerfried
4

Como han dicho Josh Lee y Colin 't Hart , opcionalmente podrías usarposition: sticky; top: 0; aplicación al div en el que deseas desplazarte ...

Además, lo único que tendrá que hacer es copiar esto en la parte superior de su página o formatearlo para que quepa en una hoja CSS externa:

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

Simplemente reemplace #sticky_div's_name_herecon el nombre de su div, es decir, si su div fuera <div id="example">, lo pondría #example { position: sticky; top: 0; }.

KalamariKing
fuente
1

Mi solución es un poco detallada, pero maneja el posicionamiento variable desde el borde izquierdo para diseños centrados.

// 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));
    });
};
Josh Russo
fuente
1

Aquí hay una versión más para probar para aquellos que tienen problemas con los demás. Reúne las técnicas discutidas en esta pregunta duplicada y genera los DIV auxiliares necesarios dinámicamente para que no se requiera HTML adicional.

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

Para hacer que un elemento sea pegajoso, haga lo siguiente:

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

Cuando el elemento se vuelve pegajoso, el código gestiona la posición del contenido restante para evitar que salte al espacio dejado por el elemento adhesivo. También devuelve el elemento adhesivo a su posición original no adhesiva cuando se desplaza hacia atrás por encima de él.

Dan
fuente
Su enfoque es muy similar al enfoque de JohnB . Teniendo en cuenta sus diferencias con esa respuesta, me pregunto (1) ¿Hay una ventaja en usar un segundo "div helper" (en lugar de solo 1 como JohnB usa) y (2) ¿Hay una ventaja en usar hide () y ¿show () en lugar de solo establecer la altura del div de ayuda (como hace JohnB)? Tal vez una diferencia de rendimiento? Hasta ahora no he podido discernir las diferencias, pero tal vez ciertos escenarios tendrían diferencias (como tal vez involucrar elementos en línea o algo así), por eso pregunto. Gracias.
Jason Frank
1

Aquí hay una versión extendida de la respuesta de Josh Lee. Si desea que el div esté en la barra lateral a la derecha y flote dentro de un rango (es decir, debe especificar las posiciones de anclaje superior e inferior). También corrige un error cuando ve esto en dispositivos móviles (debe verificar la posición de desplazamiento hacia la izquierda, de lo contrario, el div se moverá fuera de la pantalla).

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();
}
realwecan
fuente
1

Encontré esto cuando buscaba lo mismo. Sé que es una vieja pregunta, pero pensé que ofrecería una respuesta más reciente.

Scrollorama tiene una función 'pin it' que es justo lo que estaba buscando.

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

pbryd
fuente
0

La información proporcionada para responder a esta otra pregunta puede serle de ayuda, Evan:

Compruebe si el elemento es visible después de desplazarse

Básicamente, desea modificar el estilo del elemento para establecerlo como fijo solo después de haber verificado que el valor de document.body.scrollTop es igual o mayor que la parte superior de su elemento.

Ámbar
fuente
0

La respuesta aceptada funciona pero no vuelve a la posición anterior si se desplaza por encima de ella. Siempre está pegado a la parte superior después de ser colocado allí.

  $(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 respuesta de jleedev funcionaría, pero no pude hacerlo funcionar. Su página de ejemplo tampoco funcionó (para mí).

Fragua
fuente
0

Puede agregar 3 filas adicionales para que cuando el usuario vuelva a la parte superior, el div se pegue en su lugar anterior:

Aquí está el código:

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

Tengo enlaces configurados en un div, por lo que es una lista vertical de enlaces de letras y números.

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

Luego configuro esta práctica función jQuery para guardar la posición cargada y luego cambiar la posición a fija cuando se desplaza más allá de esa posición.

NOTA: ¡esto solo funciona si los enlaces están visibles en la carga de la página!

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)');
    }
});
Artistan
fuente
0

Utilicé parte del trabajo anterior para crear esta tecnología. Lo mejoré un poco y pensé en compartir mi trabajo. Espero que esto ayude.

Código 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();​

Esta es una forma un poco más dinámica de hacer el desplazamiento. Necesita algo de trabajo y en algún momento lo convertiré en un complemento, pero esto es lo que se me ocurrió después de una hora de trabajo.

newdark-it
fuente
0

En javascript puedes hacer:

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

No es una solución exacta pero es una gran alternativa a considerar

este CSS Solamente superior de la barra de desplazamiento de la pantalla . Resuelto todo el problema con SOLO CSS , NO JavaScript, NO JQuery, No Brain work ( lol ).

Disfruta mi violín : D todos los códigos están incluidos allí :)

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">

Ponga el contenido el tiempo suficiente para que pueda ver el efecto aquí :) Ah, y la referencia también está ahí, por el hecho de que merece su crédito

SOLO CSS Barra de desplazamiento de la parte superior de la pantalla

diseño weia
fuente
Un poco fuera de tema;)
Tokk
No estoy en contra de una buena solución, pero el código en su respuesta proporciona una manera de hacer que un menú se mantenga siempre en la parte superior. Pero esa no era la pregunta ...
Tokk
solo está arreglando el div y no está haciendo nada pegajoso al desplazarse.
yogihosting
0

Aquí hay un ejemplo que usa el complemento 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 (incluye el complemento 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");
    });
});
DRD
fuente
-1

pegajoso hasta que el pie de página llegue al div:

function stickyCostSummary() {
    var stickySummary = $('.sticky-cost-summary');
    var scrollCostSummaryDivPosition = $(window).scrollTop();
    var footerHeight = $('#footer').height();
    var documentHeight = $(document).height();
    var costSummaryHeight = stickySummary.height();
    var headerHeight = 83;
    var footerMargin = 10;
    var scrollHeight = 252;
    var footerPosition = $('#footer').offset().top;

    if (scrollCostSummaryDivPosition > scrollHeight && scrollCostSummaryDivPosition <= (documentHeight - footerHeight - costSummaryHeight - headerHeight - footerMargin)) {
        stickySummary.removeAttr('style');
        stickySummary.addClass('fixed');

    } else if (scrollCostSummaryDivPosition > (documentHeight - footerHeight - costSummaryHeight - headerHeight - footerMargin)) {
        stickySummary.removeClass('fixed');
        stickySummary.css({
          "position" : "absolute",
          "top" : (documentHeight - footerHeight - costSummaryHeight - headerHeight - footerMargin - scrollHeight) + "px"
      });
    } else {
        stickySummary.removeClass('fixed');
        stickySummary.css({
            "position" : "absolute",
            "top" : "0"
        });
    }
}

$window.scroll(stickyCostSummary);
Ottens
fuente