Cabeçalho de tabela para ficar fixo no topo quando o usuário rolar para fora de vista com jQuery

Estou tentando desenhar uma tabela HTML onde o cabeçalho ficará no topo da página quando E SOMENTE quando o usuário rolar para fora da visualização. Por exemplo, a tabela pode estar 500 pixels abaixo da página, como faço para que se o usuário rolar o cabeçalho para fora da vista (o navegador detecta que não está mais na vista do windows de alguma forma), ele permaneça no topo? Alguém pode me dar uma solução Javascript para isso?

<table>
  <thead>
    <tr>
      <th>Col1</th>
      <th>Col2</th>
      <th>Col3</th>
    </tr>
  </thead>
  <tbody>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
     <tr>
       <td>info</td>
       <td>info</td>
       <td>info</td>
     </tr>
  </tbody>
</table>

Portanto, no exemplo acima, quero que o <thead> role com a página se ela sair da vista.

IMPORTANTE: Eu estou **NÃO*** procurando uma solução onde o <tbody> terá uma barra de rolagem (overflow:auto).

Solução

Você faria algo assim tocando no manipulador de eventos na janela, e utilizando outra mesa com uma posição fixa para mostrar o cabeçalho no topo da página.

HTML:

<table id="header-fixed"></table>

CSS:

#header-fixed {
    position: fixed;
    top: 0px; display:none;
    background-color:white;
}

JavaScript:

var tableOffset = $("#table-1").offset().top;
var $header = $("#table-1 > thead").clone();
var $fixedHeader = $("#header-fixed").append($header);

$(window).bind("scroll", function() {
    var offset = $(this).scrollTop();

    if (offset >= tableOffset && $fixedHeader.is(":hidden")) {
        $fixedHeader.show();
    }
    else if (offset < tableOffset) {
        $fixedHeader.hide();
    }
});

Isto mostrará a cabeça da mesa quando o usuário rolar para baixo o suficiente para esconder a cabeça da mesa original. Ele irá esconder novamente quando o usuário tiver rolado a página para cima o suficiente novamente.

Exemplo de trabalho: http://jsfiddle.net/andrewwhitaker/fj8wM/

Comentários (21)

Bem, eu estava tentando obter o mesmo efeito sem recorrer a colunas de tamanho fixo ou ter uma altura fixa para toda a tabela.

A solução que eu arranjei é um hack. Consiste em duplicar toda a mesa e depois esconder tudo menos o cabeçalho, e fazer com que este tenha uma posição fixa.

HTML

<div id="table-container">
<table id="maintable">
    <thead>
        <tr>
            <th>Col1</th>
            <th>Col2</th>
            <th>Col3</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
        <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
        <tr>
            <td>info</td>
            <td>some really long line here instead</td>
            <td>info</td>
        </tr>
        <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
                <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
                <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
        <tr>
            <td>info</td>
            <td>info</td>
            <td>info</td>
        </tr>
    </tbody>
</table>
<div id="bottom_anchor"></div>
</div>
body { height: 1000px; }
thead{
    background-color:white;
}

javascript


function moveScroll(){
    var scroll = $(window).scrollTop();
    var anchor_top = $("#maintable").offset().top;
    var anchor_bottom = $("#bottom_anchor").offset().top;
    if (scroll>anchor_top && scroll
Comentários (15)

Consegui resolver o problema de mudar a largura das colunas. Comecei com a solução do Andrew's acima (muito obrigado!) e depois adicionei um pequeno loop para definir as larguras do td's clonado:

$("#header-fixed td").each(function(index){
    var index2 = index;
    $(this).width(function(index2){
        return $("#table-1 td").eq(index).width();
    });
});

Isto resolve o problema sem ter de clonar a mesa inteira e esconder o corpo. I'm novidade em JavaScript e jQuery (e para empilhar overflow), por isso qualquer comentário é apreciado.

Comentários (1)