Cabeçalhos de tabela HTML sempre visíveis na parte superior da janela ao visualizar uma tabela grande


169

Gostaria de poder "ajustar" a apresentação de uma tabela HTML para adicionar um único recurso: ao rolar a página para baixo para que a tabela fique na tela, mas as linhas do cabeçalho estejam fora da tela, gostaria que os cabeçalhos permanecessem visível na parte superior da área de visualização.

Isso seria conceitualmente semelhante ao recurso "congelar painéis" no Excel. No entanto, uma página HTML pode conter várias tabelas e eu gostaria que isso acontecesse para a tabela que está atualmente em exibição, apenas enquanto estiver em exibição.

Nota: Vi uma solução em que a área de dados da tabela é rolada enquanto os cabeçalhos não rolam. Essa não é a solução que estou procurando.


sua página foi projetada usando tabelas? não é possível convertê-lo em divs primeiro e deixar dados tabulares em paz para as tabelas?
bloquear

6
Eu escrevi recentemente um plugin que faz isso: programmingdrunk.com/floatThead
mkoryak

1
Além da solução mais votada e seus derivados abaixo, o plug-in do @mkoryak acima também é bastante bom. Certifique-se de dar uma olhada nisso também antes de terminar as "compras".
DanO 21/01

Graças dan :) Eu tenho alguns kick-ass recursos planejados para o próximo lançamento também
mkoryak

Segundo o plugin @mkoryak floatThead - pude integrá-lo rapidamente. Muito obrigado pelo plugin!
W5m

Respostas:


67

Confira jQuery.floatThead ( demos disponíveis ), que é muito legal, também pode trabalhar com DataTables e até trabalhar dentro de um overflow: autocontêiner.


sim, funciona com rolagem horizontal, rolagem de janelas, rolagem interna e redimensionamento de janelas.
Mkoryak #

Você poderia adicionar um violino com um código funcional? (Eu sei que há no local ...)
Michel Ayres

12
Eu construí uma enorme página de demonstração / documentos. Por que você precisa de um violino?
Mkoryak

5
@MustModify stackoverflow não é um bom lugar para me fazer perguntas. relate um problema no github, mesmo que seja apenas uma pergunta sobre como fazê-lo funcionar. Eu vou responder lá geralmente em menos de um dia. Aqui doente, provavelmente, responder em pouco menos de um ano :)
mkoryak

1
@MustModify pelo valor, nenhuma das classes nas tabelas nos exemplos é relevante. O plugin não precisa de nenhum css ou classe para funcionar, como dizem meus documentos.
Mkoryak # 4/16

135

Eu criei uma solução de prova de conceito usando jQuery .

Veja a amostra aqui.

Agora eu tenho esse código em um repositório de bitbucket Mercurial . O arquivo principal étables.html .

Estou ciente de um problema com isso: se a tabela contiver âncoras e se você abrir o URL com a âncora especificada em um navegador, quando a página carregar, a linha com a âncora provavelmente será obscurecida pelo cabeçalho flutuante.

Atualização 11-12-2017: Vejo que isso não funciona com o Firefox atual (57) e o Chrome (63). Não sabe quando e por que isso parou de funcionar ou como corrigi-lo. Mas agora, acho que a resposta aceita por Hendy Irawan é superior.


Eu precisava disso para algo que estou fazendo. Grande ajuda, obrigado. Na minha, eu não estava usando a janela, pois o painel de rolagem era uma div dentro do html. Então, tive que mudar floatingHeaderRow.css("top", Math.min(scrollTop - offset.top, $(this).height() - floatingHeaderRow.height()) + "px");para floatingHeaderRow.css("top", scrollTop + "px");o código que você tinha, o cabeçalho da tabela estava pulando mais abaixo na página para eventualmente desaparecer da página.
Nalum 07/07

1
Eu estou tentando implementar isso na minha tabela. Estou tendo um problema com a largura do cabeçalho. Os dados nas linhas são valores extraídos de um banco de dados, pois são de tamanho aleatório. Antes de rolar, os cabeçalhos têm o tamanho herdado automaticamente, mas uma vez que você rola, os cabeçalhos são redimensionados para contornar os nomes dos cabeçalhos e, portanto, têm uma largura muito menor para que os cabeçalhos não sejam realmente rastreados por cima dos respectivos coluna. Como posso corrigir esse problema?
precisa saber é o seguinte

Hmm, não tenho certeza, com base na sua descrição. Sugiro 1) se possível, mostre um exemplo online; 2) faça isso como uma pergunta no StackOverflow.
Craig McQueen

@ JonYork Eu tive exatamente o mesmo problema. Meu problema foi usar <td> no cabeçalho em vez de <th>, para que não pudesse aplicar a largura de cada coluna a <th> inexistente (consulte // Copy cell widths from original headerparte do código). @ Craig McQueen, edite sua resposta para que ninguém mais cometa esse erro.
Aexl

@CraigMcQueen Quando uso seu código incrível (obrigado), ele quebra na segunda tabela que tenho, que fica atrás de outra guia (plugin da guia jQuery). Alguma ideia? O cabeçalho é colocado na extrema esquerda, em vez de seguir as colunas de localização. Mas funciona perfeitamente em cima da mesa na primeira guia jQuery.
Richard Żak

68

Craig, refinei um pouco o seu código (entre algumas outras coisas que ele agora está usando position: fixed) e o envolvi como um plugin do jQuery.

Experimente aqui: http://jsfiddle.net/jmosbech/stFcx/

E obtenha a fonte aqui: https://github.com/jmosbech/StickyTableHeaders


1
Boa idéia para criar um plugin jQuery. Algumas perguntas: (1) Funciona bem com rolagem horizontal? (2) Como se comporta quando você rola para baixo, de modo que a parte inferior da tabela esteja rolando para fora da parte superior da janela? O exemplo não permite testar esses casos.
Craig McQueen

Seu exemplo do jsfiddle funciona muito bem com o tablesorter, mas o código no github não. Você teve que modificar o código do tablesorter?
21711 Ericslaw #

Craig, a rolagem horizontal não deve ser um problema, pois o cabeçalho é reposicionado horizontal e verticalmente na rolagem e no redimensionamento. Quanto à sua segunda pergunta: o cabeçalho fica oculto quando a tabela sai da janela de visualização.
Jsbech #

Eric, isso é estranho. Você tentou abrir o /demo/tablesorter.htm no Github? Não modifiquei o código do tablesorter, mas para fazê-lo funcionar, é necessário aplicar o plug-in StickyTableHeader antes do tablesorter.
Jsbech #

2
A rolagem horizontal não funciona muito bem, depois de rolar bastante a distância, o cabeçote é posicionado mais à esquerda quando rolado para fora da tela do que quando é posicionado normalmente como parte da tabela.
Nathan Phillips

16

Se você estiver segmentando navegadores modernos compatíveis com css3 ( suporte ao navegador: https://caniuse.com/#feat=css-sticky ), poderá usarposition:sticky , o que não requer JS e não prejudica o layout da tabela. e td da mesma coluna. Também não requer largura fixa da coluna para funcionar corretamente.

Exemplo para uma única linha de cabeçalho:

thead th
{
    position: sticky;
    top: 0px;
}

Para segmentos com 1 ou 2 linhas, você pode usar algo como isto:

thead > :last-child th
{
    position: sticky;
    top: 30px; /* This is for all the the "th" elements in the second row, (in this casa is the last child element into the thead) */
}

thead > :first-child th
{
    position: sticky;
    top: 0px; /* This is for all the the "th" elements in the first child row */
}

Pode ser necessário jogar um pouco com o topo propriedade do último filho, alterando o número de pixels para corresponder à altura da primeira linha (+ a margem + a borda + o preenchimento, se houver), para que a segunda linha fique abaixo abaixo o primeiro.

Além disso, ambas as soluções funcionam mesmo se você tiver mais de uma tabela na mesma página: o th elemento de cada uma começa a ficar pegajoso quando sua posição superior é a indicada na definição de css e desaparece quando toda a tabela rola para baixo. Portanto, se houver mais tabelas, todas funcionam lindamente da mesma maneira.

Por que usar o último filho antes e o primeiro filho depois no css?

Como as regras css são renderizadas pelo navegador na mesma ordem em que você as escreve no arquivo css, por isso, se você tiver apenas 1 linha no elemento thead, a primeira linha também será a última linha e a regra do primeiro filho também precisará para substituir o último filho. Caso contrário, você terá um deslocamento da linha 30 px da margem superior, que suponho que não queira.

Um problema conhecido de posição: pegajoso é que ele não funciona nos elementos do cabeçalho ou nas linhas da tabela: você deve direcionar os elementos. Pular esse problema será resolvido em versões futuras do navegador.


O primeiro exemplo não parece funcionar no Firefox (61). No entanto, se a posição pegajosa estiver definida no cabeçote, isso ocorrerá.
EWH

1
Você poderia fazer thead tr+tr thpara segmentar a segunda linha.
Teepeemm

5

Alternativas possíveis

js-floating-table-headers

js-floating-table-headers (Código do Google)

No Drupal

Eu tenho um site do Drupal 6. Eu estava na página "módulos" do administrador e percebi que as tabelas tinham esse recurso exato!

Olhando para o código, parece ser implementado por um arquivo chamado tableheader.js. Aplica o recurso em todas as tabelas da classe sticky-enabled.

Para um site Drupal, eu gostaria de poder usar esse tableheader.jsmódulo como está no conteúdo do usuário. tableheader.jsparece não estar presente nas páginas de conteúdo do usuário no Drupal. Publiquei uma mensagem no fórum para perguntar como modificar o tema do Drupal para que fique disponível. De acordo com uma resposta, tableheader.jspode ser adicionado a um tema Drupal usando drupal_add_js()no tema da template.phpseguinte maneira:

drupal_add_js('misc/tableheader.js', 'core');

Seu link do Google Code foi muito útil para mim, tahnks.
Vilius Gaidelis

5

Encontrei esse problema muito recentemente. Infelizmente, eu tive que fazer 2 mesas, uma para o cabeçalho e outra para o corpo. Provavelmente não é a melhor abordagem de todos os tempos, mas aqui vai:

<html>
<head>
    <title>oh hai</title>
</head>
<body>
    <table id="tableHeader">
        <tr>
            <th style="width:100px; background-color:#CCCCCC">col header</th>
            <th style="width:100px; background-color:#CCCCCC">col header</th>
        </tr>
    </table>
    <div style="height:50px; overflow:auto; width:250px">
        <table>
            <tr>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data1</td>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data1</td>
            </tr>
            <tr>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data2</td>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data2</td>
            </tr>
        </table>
    </div>
</body>
</html>

Isso funcionou para mim, provavelmente não é a maneira elegante, mas funciona. Vou investigar para ver se posso fazer algo melhor, mas isso permite várias tabelas.

Leia a propriedade do estouro para ver se ela se adapta às suas necessidades


Hmm não funciona, eu vou tentar corrigir isso, mas os restos de abordagem, você tem que usar o overflow: auto proprety
Gab Royer

Aprecio sua solução e sua simplicidade, no entanto, na minha pergunta, eu disse: "Observação: vi uma solução em que a área de dados da tabela é rolada enquanto os cabeçalhos não rolam. Essa não é a solução que estou procurando".
Craig McQueen

@GabRoyer A página w3school, você referenciou, não existe.
Farhan 04/04

Eles parecem ter se mudado. Corrigido
Gab Royer 05/09

Outro problema dessa abordagem é que, se você precisar adaptar algumas das colunas a outro conteúdo, corre o risco de interromper o alinhamento delas com o cabeçalho da coluna correspondente. IMHO, é melhor enfrentar esse problema com uma abordagem que permita um gerenciamento dinâmico do conteúdo, que mantenha um alinhamento perfeito de colunas e cabeçalhos relativos. Então, a posição IMHO = pegajosa é o caminho a percorrer.
Willy wonka

3

É realmente uma coisa complicada ter um cabeçalho pegajoso na sua mesa. Eu tinha o mesmo requisito, mas com asp: GridView e, em seguida, achei que ele realmente tinha cabeçalho pegajoso no gridview. Existem muitas soluções disponíveis e demorei 3 dias a tentar toda a solução, mas nenhuma delas conseguiu satisfazer.

O principal problema que enfrentei com a maioria dessas soluções foi o problema de alinhamento. Quando você tenta fazer o cabeçalho flutuar, de alguma forma o alinhamento das células do cabeçalho e do corpo fica fora do controle.

Com algumas soluções, também tive o problema de sobrepor o cabeçalho às primeiras linhas do corpo, o que faz com que as linhas do corpo fiquem ocultas atrás do cabeçalho flutuante.

Então agora eu tive que implementar minha própria lógica para conseguir isso, embora eu também não considere isso uma solução perfeita, mas isso também possa ser útil para alguém,

Abaixo está a tabela de amostra.

<div class="table-holder">
        <table id="MyTable" cellpadding="4" cellspacing="0" border="1px" class="customerTable">
            <thead>
                <tr><th>ID</th><th>First Name</th><th>Last Name</th><th>DOB</th><th>Place</th></tr>
            </thead>
            <tbody>
                <tr><td>1</td><td>Customer1</td><td>LastName</td><td>1-1-1</td><td>SUN</td></tr>
                <tr><td>2</td><td>Customer2</td><td>LastName</td><td>2-2-2</td><td>Earth</td></tr>
                <tr><td>3</td><td>Customer3</td><td>LastName</td><td>3-3-3</td><td>Mars</td></tr>
                <tr><td>4</td><td>Customer4</td><td>LastName</td><td>4-4-4</td><td>Venus</td></tr>
                <tr><td>5</td><td>Customer5</td><td>LastName</td><td>5-5-5</td><td>Saturn</td></tr>
                <tr><td>6</td><td>Customer6</td><td>LastName</td><td>6-6-6</td><td>Jupitor</td></tr>
                <tr><td>7</td><td>Customer7</td><td>LastName</td><td>7-7-7</td><td>Mercury</td></tr>
                <tr><td>8</td><td>Customer8</td><td>LastName</td><td>8-8-8</td><td>Moon</td></tr>
                <tr><td>9</td><td>Customer9</td><td>LastName</td><td>9-9-9</td><td>Uranus</td></tr>
                <tr><td>10</td><td>Customer10</td><td>LastName</td><td>10-10-10</td><td>Neptune</td></tr>
            </tbody>
        </table>
    </div>

Nota : A tabela é agrupada em um DIV com o atributo de classe igual a 'table-holder'.

Abaixo está o script JQuery que eu adicionei no cabeçalho da página html.

<script src="../Scripts/jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="../Scripts/jquery-ui.min.js" type="text/javascript"></script>
<script type="text/javascript">
    $(document).ready(function () {
        //create var for table holder
        var originalTableHolder = $(".table-holder");
        // set the table holder's with
        originalTableHolder.width($('table', originalTableHolder).width() + 17);
        // Create a clone of table holder DIV
        var clonedtableHolder = originalTableHolder.clone();

        // Calculate height of all header rows.
        var headerHeight = 0;
        $('thead', originalTableHolder).each(function (index, element) {
            headerHeight = headerHeight + $(element).height();
        });

        // Set the position of cloned table so that cloned table overlapped the original
        clonedtableHolder.css('position', 'relative');
        clonedtableHolder.css('top', headerHeight + 'px');

        // Set the height of cloned header equal to header height only so that body is not visible of cloned header
        clonedtableHolder.height(headerHeight);
        clonedtableHolder.css('overflow', 'hidden');

        // reset the ID attribute of each element in cloned table
        $('*', clonedtableHolder).each(function (index, element) {
            if ($(element).attr('id')) {
                $(element).attr('id', $(element).attr('id') + '_Cloned');
            }
        });

        originalTableHolder.css('border-bottom', '1px solid #aaa');

        // Place the cloned table holder before original one
        originalTableHolder.before(clonedtableHolder);
    });
</script>

e finalmente abaixo está a classe CSS para fins de coloração.

.table-holder
{
    height:200px;
    overflow:auto;
    border-width:0px;    
}

.customerTable thead
{
    background: #4b6c9e;        
    color:White;
}

Portanto, toda a idéia dessa lógica é colocar a tabela em uma div do suporte da tabela e criar clone desse suporte no lado do cliente quando a página for carregada. Agora, oculte o corpo da tabela dentro do suporte do clone e posicione a parte restante do cabeçalho sobre o cabeçalho original.

A mesma solução também funciona para asp: gridview, você precisa adicionar mais duas etapas para conseguir isso no gridview,

  1. No evento OnPrerender do objeto gridview em sua página da web, defina a seção da tabela da linha do cabeçalho igual a TableHeader.

    if (this.HeaderRow != null)
    {
        this.HeaderRow.TableSection = TableRowSection.TableHeader;
    }
  2. E envolva sua grade <div class="table-holder"></div>.

Nota : se o cabeçalho tiver controles clicáveis, talvez seja necessário adicionar mais um script jQuery para passar os eventos gerados no cabeçalho clonado para o cabeçalho original. Esse código já está disponível no plugin jQuery sticky-header criado por jmosbech


+1 para bom esforço, mas para grandes tabelas com muitos dados, é muito ruim para clonar a coisa toda ... Imagino que dobraria o tempo de carregamento
khaverim

2

O uso display: fixedda theadseção deve funcionar, mas, para funcionar apenas na tabela atual em exibição, você precisará da ajuda do JavaScript. E será complicado, pois será necessário descobrir os locais de rolagem e a localização dos elementos em relação à janela de visualização, que é uma das principais áreas de incompatibilidade do navegador.

Dê uma olhada nas estruturas JavaScript populares (jQuery, MooTools, YUI, etc etc.) para ver se elas podem fazer o que você deseja ou torná-lo mais fácil.


1
Obrigado pelo conselho. Eu fiz uma solução usando jQuery - veja minha resposta.
Craig McQueen

Eu tentei isso e estou pensando que você quis dizer posição ao invés de exibição, mas nenhum deles funcionou para o thome no chome.
ericslaw

@ericslaw Ack - sim, eu quis dizer position: fixed. Lamentamos, mas não funcionou no Chrome.
Staticsan

confuso meu cabeçalho ignorando largura estilos
pavel_kazlou

2

Se você usa uma tabela em tela cheia, talvez esteja interessado em definir a opção para exibir: fixo; e superior: 0; ou tente uma abordagem muito semelhante via css.

Atualizar

Crie rapidamente uma solução funcional com iframes (html4.0). Este exemplo NÃO está em conformidade com o padrão, mas você poderá corrigi-lo facilmente:

outer.html

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">   
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">     
    <head>      
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />   
        <title>Outer</title>
  <body>
    <iframe src="test.html" width="200" height="100"></iframe>
    </body>
</html> 

test.html

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">   
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">     
    <head>      
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />   
        <title>Floating</title>
    <style type="text/css">
      .content{
        position:relative; 
      }

      thead{
        background-color:red;
        position:fixed; 
        top:0;
      }
    </style>
  <body>
    <div class="content">      
      <table>
        <thead>
          <tr class="top"><td>Title</td></tr>
        </head>
        <tbody>
          <tr><td>a</td></tr>
          <tr><td>b</td></tr>
          <tr><td>c</td></tr>
          <tr><td>d</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
        </tbody>
      </table>
    </div>
    </body>
</html> 

@ a_m0d, é verdade ... mas a solicitação parece muito confusa. Ou estamos entendendo errado, ou o solicitante não entende completamente o que quer.
Sampson

Aqui é uma outra solução usando algum javascript imaputz.com/cssStuff/bigFourVersion.html
merkuro

2

A resposta mais simples usando apenas CSS: D !!!

table {
  /* Not required only for visualizing */
  border-collapse: collapse;
  width: 100%;
}

table thead tr th {
  /* you could also change td instead th depending your html code */
  background-color: green;
  position: sticky;
  z-index: 100;
  top: 0;
}

td {
  /* Not required only for visualizing */
  padding: 1em;
}
<table>
  <thead>
    <tr>
      <th>Col1</th>
      <th>Col2</th>
      <th>Col3</th>
    </tr>
  </thead>
  <tbody>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>data</td>
       <td>data</td>
       <td>data</td>
     </tr>
     <tr>
       <td>david</td>
       <td>castro</td>
       <td>rocks!</td>
     </tr>
  </tbody>
</table>


1
Obrigado David, é a melhor abordagem que encontrei nesta pergunta
Tomasz Smykowski

0

Essa prova de conceito que você criou foi ótima! No entanto, eu também encontrei este plugin jQuery, que parece estar funcionando muito bem. Espero que ajude!


Parece que implementa um recurso diferente . Como disse na minha pergunta original: "Nota: vi uma solução em que a área de dados da tabela é rolada enquanto os cabeçalhos não rolam. Essa não é a solução que estou procurando".
Craig McQueen

2
tentando o plugin que você mencionou acabou de mexer no meu cabeçalho da tabela. Não foi capaz de usá-lo.
23411 Pavel_kazlou

0

É frustrante que o que funciona bem em um navegador não funcione em outros. O seguinte funciona no Firefox, mas não no Chrome ou IE:

<table width="80%">

 <thead>

 <tr>
  <th>Column 1</th>
  <th>Column 2</th>
  <th>Column 3</th>
 </tr>

 </thead>

 <tbody style="height:50px; overflow:auto">

  <tr>
    <td>Cell A1</td>
    <td>Cell B1</td>
    <td>Cell C1</td>
  </tr>

  <tr>
    <td>Cell A2</td>
    <td>Cell B2</td>
    <td>Cell C2</td>
  </tr>

  <tr>
    <td>Cell A3</td>
    <td>Cell B3</td>
    <td>Cell C3</td>
  </tr>

 </tbody>

</table>

4
Estou tentando no Firefox 8.0 e parece que não faz nada. O que isso faz?
Craig McQueen

O que é px? É essa unidade herdada usada pelas pessoas no dia 90 quando um dispositivo de exibição era usado para ter 72 dpi?
ceving 11/10/16

Concordo: é muito frustrante. Infelizmente, os desenvolvedores de navegadores não respeitam os padrões em todas as situações ... e há alguns anos foi ainda pior! Agora, alguns problemas foram resolvidos e mais navegadores se comportam de maneira mais padronizada, mas ainda há muitos passos a serem feitos: vamos torcer e orar :-)
willy wonka
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.