Como posso fazer uma div ficar na parte superior da tela depois de rolada?

305

Gostaria de criar uma div, situada abaixo de um bloco de conteúdo, mas que, uma vez que a página tenha sido rolada o suficiente para entrar em contato com seu limite superior, fique fixa no local e role com a página.

evanr
fonte
5
Em junho de 2014, o plug - in Sticky-kit jQuery é uma das opções mais fáceis, fornecendo uma barreira extremamente baixa à entrada e muitos recursos. Ótimo lugar para começar, se você estiver procurando uma maneira fácil de sair do chão rapidamente.
user456584
1
Truques CSS: css-tricks.com/scroll-fix-content
Ciro Santilli ()
32
Adicionando CSS position: sticky; top:0;funciona na maioria dos navegadores em janeiro de 2017.
Colin 't Hart
9
Caramba, isso position: sticky;é mágico.
tscizzle

Respostas:

259

Você pode usar simplesmente css, posicionando seu elemento como fixo :

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

Editar: você deve ter o elemento com posição absoluta; assim que o deslocamento da rolagem atingir o elemento, ele deve ser alterado para fixo e a posição superior deve ser definida como zero.

Você pode detectar o deslocamento da rolagem superior do documento com a função 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'}); 
  } 
});

Quando o deslocamento da rolagem atingiu 200, o elemento gruda na parte superior da janela do navegador, porque é colocado como fixo.

CMS
fonte
4
isso não alcança o que estou buscando. Gostaria que o elemento iniciasse a 200px abaixo da parte superior da página (para permitir espaço para outro conteúdo) e, depois que o usuário rolar para baixo, fique fixo na parte superior.
evanr
3
sua edição realmente atende às necessidades da pergunta agora, mas você ainda tem um problema quando a página retorna ao topo novamente. você pode, depois de alcançar o elemento scrollTop, armazená-lo em algum lugar e, quando a página atingir essa posição novamente (ao rolar para cima), mudar o css de volta ao padrão ... provavelmente é melhor fazer isso com um .toggleClass ...
Sander
9
Isso é praticamente o que quando, mas eu tive que remover o posicionamento fixo quando a janela é rolada de volta para o topo. if ($(this).scrollTop() < 200 && $el.css('position') == 'fixed') { $('.fixedElement').css({'position': 'static', 'top': '0px'}); }
Derrick Petzold
1
@DerrickPetzold eu colocar isso em resposta, bastante coisas importantes :)
MarioDS
1
o new examplelink que você deu é tão limpo e claro que eu nem consigo vê-lo! -_-
sohaiby
245

Você viu este exemplo na página de problemas do Google Code e (apenas recentemente) na página de edição do Stack Overflow.

A resposta do CMS não reverte o posicionamento quando você rolar para cima. Aqui está o código descaradamente roubado do 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> 

E uma simples demonstração ao vivo .

Uma alternativa nascente e sem scripts position: stickyé suportada no Chrome, Firefox e Safari. Veja o artigo sobre HTML5Rocks e demo e os documentos da Mozilla .

Josh Lee
fonte
3
Por alguma razão, o {scroll: false} estava me causando problemas (jQuery 1.6.2). Parece funcionar sem ele. Garfo de demonstração vinculada. Alguma idéia se serve a um propósito?
Eddie
Estou tendo muitos problemas com isso, por toda a vida que não consigo replicar, tentei replicar a demonstração ao vivo e ela não está funcionando. alguém pode criar um link para um tutorial que fornece instruções passo a passo?
Trevor Dupp
2
Isso parece funcionar muito bem quando eu uso a mesma versão do jQuery que a demo (1.3.2). Em algum momento offsetdeve ter parado de aceitar um objeto como entrada api.jquery.com/offset . @ Eddie Sua modificação deve ser segura com o jQuery atual.
Graeme
1
Existe algum motivo você não poderia substituir var d = $("#scroller-anchor").offset().top;com var d = $("#sidebar").offset().top;e se livrar do div scroller-âncora vazia todos juntos? Aqui está o meu garfo demonstrando o que estou falando.
Mike plataforma
@ MikeDeck Eu suspeito que, se houver margens ou preenchimento, você gostaria de controlar onde o scroller está posicionado em relação ao contêiner.
Josh Lee
72

Desde janeiro de 2017 e o lançamento do Chrome 56, a maioria dos navegadores de uso comum suporta a position: stickypropriedade em CSS.

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

faz o truque para mim no Firefox e Chrome.

No Safari, você ainda precisa usar position: -webkit-sticky.

Polyfills estão disponíveis para Internet Explorer e Edge; https://github.com/wilddeer/stickyfill parece ser bom.

Colin 't Hart
fonte
5
Isso é suportado na maioria dos navegadores de uso comum hoje. Veja caniuse.com/#feat=css-sticky Em segundo lugar, prefiro uma solução que pode ser resumida em duas linhas de código a uma versão que requer Javascript personalizado. E é à prova de futuro também. Use um polyfill se estiver preocupado com a compatibilidade do navegador.
Colin 't Hart
1
Não pode ser mais fácil do que isso :)
mestarted
1
Gostaria de acrescentar a este comentário que podemos z-index: 99999 ;, porque, se não for quando for para o topo, o outro conteúdo será renderizado primeiro. Mas essa deve ser a solução aceita.
dayanrr91
Apenas envolva-o em uma div com id = "thing_to_stick"
Anton
Solução simples e fácil. E funciona melhor do que outras soluções no meu caso, é claro.
fsevenm 30/03
33

Eu tive o mesmo problema que você e acabei criando um plugin jQuery para cuidar dele. Na verdade, ele resolve todos os problemas que as pessoas listaram aqui, além de adicionar alguns recursos opcionais.

Opções

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.
fonte
1
Ei! Obrigado! Esta é uma ótima solução, e obrigado por compartilhar, com certeza me salvou muito tempo. Essa deve ser a solução geral aceita para esta pergunta, pois, até onde eu li, é a solução mais completa. Basicamente, os outros não resolveram o problema com a posição X original de um bloco após a posição: estilo fixo é aplicado. O seu resolve esse problema. Realmente, muito obrigado!
Marcos Buarque
Ei, Donny, também adorei o seu plug-in (v1.4.1) ... deparei com um problema, os elementos de bloco perdiam a largura se nenhum deles fosse especificado. Assim, alterou-a ao desconectar ... apenas definindo a largura para que permaneça a mesma. code// desanexar o painel node.css ({"margin": 0, "left": nodeLeft, "top": newNodeTop, "position": "fixed", "width": node.width ()}); code
perfil completo de Will Hancock
Procurou e tentou muitas soluções, e isso funcionou "imediatamente". Ótimo trabalho! Obrigado!
precisa saber é
2
@WillHancock Adicionei suporte para iPad, corrigi o bug de atualização e adicionei eventos onDetached e onReattached. Os novos eventos darão acesso ao painel e spacerpanel depois que ele for desconectado e reconectado.
Donny V.
4
Também foi adicionada uma opção parentSelector para suportar divs de rolagem.
quer
24

E aqui está como sem o jquery (UPDATE: veja outras respostas onde agora você pode fazer isso apenas com 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 diz que restabelece Monica
fonte
4
Obrigado! Hoje em dia é difícil encontrar soluções JS nativas. Isso funcionou perfeitamente.
Sherri
Muito obrigado, isso funcionou perfeitamente, pois jquery estava em conflito com algum código corporativo herdado que meu projeto tem
sng
apesar de estar com um problema em que, se eu rolar até a parte inferior da página, ela automaticamente voltará ao topo.
SNG
@sng Minha página de amostra faz isso?
Jim W diz que restabelece Monica
@ JimW eu descobri o problema. Eu estava tentando usá-lo com uma barra de menus com base vertical ao lado de uma div de conteúdo principal à esquerda. Ele estava com problemas quando você rola para baixo, pois não pode determinar quando está atingindo a parte inferior da página corretamente. Acabei de adicionar uma linha de código para definir a altura div recipiente para o tamanho da tela da janela para o ouvinte de evento scroll
SNG
9

Foi assim que fiz com jquery. Tudo isso foi elaborado a partir de várias respostas no estouro da pilha. Essa solução armazena em cache os seletores para obter um desempenho mais rápido e também resolve o problema de "pular" quando a div fixa fica pegajosa.

Confira em 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
fonte
7

Aqui está outra opção:

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

Você #myElementToStickdeve começar com a position:absolutepropriedade CSS.

kunde
fonte
1
Penso que esta é uma solução muito limpa e fácil. Eu simplesmente não posicionaria o elemento "absoluto" - isso pode quebrar o layout - eu apenas o definiria como estático.
Gerfried
4

Como Josh Lee e Colin 'Hart disseram, você pode opcionalmente usar a position: sticky; top: 0;aplicação na div em que deseja a rolagem ...

Além disso, a única coisa que você precisará fazer é copiar isso no topo da página ou formatá-lo para caber em uma folha CSS externa:

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

Apenas substitua #sticky_div's_name_herepelo nome da sua div, ou seja, se sua div fosse, <div id="example">você colocaria #example { position: sticky; top: 0; }.

KalamariKing
fonte
1

Minha solução é um pouco detalhada, mas lida com o posicionamento variável da borda esquerda para layouts centralizados.

// 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
fonte
1

Aqui está mais uma versão para tentar para aqueles que têm problemas com os outros. Ele reúne as técnicas discutidas nesta pergunta duplicada e gera dinamicamente as DIVs auxiliares necessárias, para que nenhum HTML extra seja necessário.

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 tornar um elemento grudento, faça:

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

Quando o elemento fica pegajoso, o código gerencia a posição do conteúdo restante para evitar que ele salte para o espaço deixado pelo elemento pegajoso. Ele também retorna o elemento adesivo à sua posição original não adesivo ao rolar para trás acima dele.

Dan
fonte
Sua abordagem é muito semelhante à abordagem de JohnB . Considerando suas diferenças em relação a essa resposta, estou pensando (1) existe uma vantagem em usar uma segunda "helper div" (em vez de apenas 1 como JohnB usa) e (2) existe uma vantagem em usar hide () e show () em vez de apenas definir a altura da div auxiliar (como JohnB faz)? Talvez uma diferença de desempenho? Até agora, não consegui discernir diferenças, mas talvez alguns cenários tenham diferenças (como envolver elementos inline ou algo assim), por isso pergunto. Obrigado.
Jason Frank
1

Aqui está uma versão estendida da resposta de Josh Lee. Se você deseja que a div esteja na barra lateral à direita e flutue dentro de um intervalo (ou seja, é necessário especificar as posições de ancoragem superior e inferior). Ele também corrige um erro quando você o exibe em dispositivos móveis (você precisa verificar a posição de rolagem esquerda, caso contrário, a div sairá da tela).

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
fonte
1

Me deparei com isso ao procurar a mesma coisa. Sei que é uma pergunta antiga, mas pensei em oferecer uma resposta mais recente.

O Scrollorama tem um recurso 'fixe', que é exatamente o que eu estava procurando.

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

pbryd
fonte
0

As informações fornecidas para responder a essa outra pergunta podem ser úteis para você, Evan:

Verifique se o elemento está visível após a rolagem

Basicamente, você deseja modificar o estilo do elemento para defini-lo como fixo somente depois de verificar se o valor document.body.scrollTop é igual ou superior à parte superior do seu elemento.

Âmbar
fonte
0

A resposta aceita funciona, mas não volta à posição anterior se você rolar acima dela. É sempre preso ao topo depois de ser colocado lá.

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

A resposta de jleedev daria certo, mas não consegui fazê-la funcionar. Sua página de exemplo também não funcionou (para mim).

Forja
fonte
0

Você pode adicionar 3 linhas extras para que, quando o usuário rolar de volta para o topo, a div fique no seu antigo local:

Aqui está o código:

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

Eu tenho links configurados em uma div, por isso é uma lista vertical de links de letras e números.

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

Em seguida, configurei esta útil função jQuery para salvar a posição carregada e, em seguida, alterei a posição para fixa ao rolar além dessa posição.

NOTA: isso só funciona se os links estiverem visíveis no carregamento da 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
fonte
0

Eu usei alguns dos trabalhos acima para criar essa tecnologia. Melhorei um pouco e pensei em compartilhar meu trabalho. Espero que isto ajude.

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 é uma maneira um pouco mais dinâmica de fazer a rolagem. Ele precisa de algum trabalho e, em algum momento, vou transformá-lo em um plug-in, mas é isso que eu descobri após uma hora de trabalho.

newdark-it
fonte
0

Em javascript, você pode fazer:

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

Não é uma solução exata, mas uma ótima alternativa a considerar

essa CSS SOMENTE Barra de rolagem na parte superior da tela . Resolvido todo o problema com apenas CSS , NO JavaScript, NO JQuery, No Brain ( lol ).

Aproveite o meu violino : D todos os códigos estão incluídos lá :)

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

Coloque o conteúdo por tempo suficiente para que você possa ver o efeito aqui :) Ah, e a referência também está lá, porque ele merece seu crédito

SOMENTE CSS Barra de rolagem na parte superior da tela

weia design
fonte
Um pouco offtopic;)
Tokk
Não sou contra uma boa solução, mas o código na sua resposta fornece uma maneira de criar algo como um menu para sempre ficar no topo. Mas essa não era a questão ...
Tokk
você está apenas consertando a div e não fazendo nada pegajoso na rolagem.
yogihosting 9/11/2015
0

Aqui está um exemplo que usa o 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 (inclua o 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");
    });
});
DRD
fonte
-1

pegajoso até o rodapé atingir a 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
fonte