Como exibir a barra de rolagem em uma tabela html

86

Estou escrevendo uma página onde preciso de uma tabela html para manter um tamanho definido. Preciso que os cabeçalhos na parte superior da tabela permaneçam lá o tempo todo, mas também preciso que o corpo da tabela role, independentemente de quantas linhas sejam adicionadas à tabela.

Quero que se pareça com o método 2 neste url: http://www.cssplay.co.uk/menu/tablescroll.html

Eu tentei fazer isso, mas nenhuma barra de rolagem aparece:

tbody {
  height: 80em;
  overflow: scroll;
}
<table border=1 id="qandatbl" align="center">
  <tr>
    <th class="col1">Question No</th>
    <th class="col2">Option Type</th>
    <th class="col1">Duration</th>
  </tr>

  <tbody>
    <tr>
      <td class='qid'></td>
      <td class="options"></td>
      <td class="duration"></td>
    </tr>
  </tbody>
</table>

BruceyBandit
fonte
Por que você não usa o código do método de exemplo? Você não pode usar, <tbody>infelizmente.
Mike Park

Respostas:

164

Algo assim?

http://jsfiddle.net/TweNm/

A ideia é envolver o <table>em um posicionado não estaticamente <div>que possua uma overflow:autopropriedade CSS. Em seguida, posicione os elementos no <thead>absolutamente.

#table-wrapper {
  position:relative;
}
#table-scroll {
  height:150px;
  overflow:auto;  
  margin-top:20px;
}
#table-wrapper table {
  width:100%;

}
#table-wrapper table * {
  background:yellow;
  color:black;
}
#table-wrapper table thead th .text {
  position:absolute;   
  top:-20px;
  z-index:2;
  height:20px;
  width:35%;
  border:1px solid red;
}
<div id="table-wrapper">
  <div id="table-scroll">
    <table>
        <thead>
            <tr>
                <th><span class="text">A</span></th>
                <th><span class="text">B</span></th>
                <th><span class="text">C</span></th>
            </tr>
        </thead>
        <tbody>
          <tr> <td>1, 0</td> <td>2, 0</td> <td>3, 0</td> </tr>
          <tr> <td>1, 1</td> <td>2, 1</td> <td>3, 1</td> </tr>
          <tr> <td>1, 2</td> <td>2, 2</td> <td>3, 2</td> </tr>
          <tr> <td>1, 3</td> <td>2, 3</td> <td>3, 3</td> </tr>
          <tr> <td>1, 4</td> <td>2, 4</td> <td>3, 4</td> </tr>
          <tr> <td>1, 5</td> <td>2, 5</td> <td>3, 5</td> </tr>
          <tr> <td>1, 6</td> <td>2, 6</td> <td>3, 6</td> </tr>
          <tr> <td>1, 7</td> <td>2, 7</td> <td>3, 7</td> </tr>
          <tr> <td>1, 8</td> <td>2, 8</td> <td>3, 8</td> </tr>
          <tr> <td>1, 9</td> <td>2, 9</td> <td>3, 9</td> </tr>
          <tr> <td>1, 10</td> <td>2, 10</td> <td>3, 10</td> </tr>
          <!-- etc... -->
          <tr> <td>1, 99</td> <td>2, 99</td> <td>3, 99</td> </tr>
        </tbody>
    </table>
  </div>
</div>

Richard JP Le Guen
fonte
15
Que tal sem colunas com largura fixa?
Fractaliste de
3
Tentei sua resposta, mas as colunas do cabeçalho não estão alinhadas. Usei apenas seu css em uma tag de estilo dentro da tag body onde copiei sua tabela
Antonio
Ótima solução, mas estou tendo problemas com isso. Ao tentar ocultar uma linha e definir a exibição: nenhum, há alguns espaços em branco entre as linhas. Esse não é o caso da mesa regular. Alguma ideia, dica ou sugestão?
Daniil Shevelev 01 de
@Antonio: Eu tive o mesmo problema (colunas de cabeçalho centradas * parecendo não alinhadas), mas adicionar transform: translateX(-50%)funcionou para mim [* centrado sendo o estilo padrão do Firefox que é removido pela opção „normalizar CSS“ no JSFiddle desta resposta]
Sora.
46

Você tem que inserir seu <table>em um <div>que tenha tamanho fixo e com <div>estilo que você tem que definir overflow: scroll.

Hossein Barzegari
fonte
1
deu a altura de 500px para meu div e funcionou bem. <div style = "overflow: scroll; height: 500px;">
Ziggler
3
Não sei por que todo mundo tornou isso tão complicado. Esta deve ser a resposta aceita.
amallard de
1
Esta é de longe a solução mais fácil. Pode haver advertências para adicionar um div com um estouro e altura fixa, mas essa solução pelo menos o colocará na direção certa.
lsimonetti
1
Excelente resposta, companheiro! Saudações a você
:)
1
Esta deve ser a resposta aceita. Simples, direto ao ponto e não destruo mais nada com ele.
Eu tento tanto, mas choro mais ainda,
40

A resposta aceita forneceu um bom ponto de partida, mas se você redimensionar o quadro, alterar a largura das colunas ou mesmo alterar os dados da tabela, os cabeçalhos ficarão bagunçados de várias maneiras. Todos os outros exemplos que vi têm problemas semelhantes ou impõem algumas restrições sérias ao layout da mesa.

Acho que finalmente resolvi todos esses problemas. Exigiu muito CSS, mas o produto final é tão confiável e fácil de usar quanto uma mesa normal.

Aqui está um exemplo que possui todos os recursos necessários para replicar a tabela referenciada pelo OP: jsFiddle

As cores e bordas teriam que ser alteradas para torná-lo idêntico à referência. Informações sobre como fazer esses tipos de alterações são fornecidas nos comentários do CSS.

Aqui está o código:

/*the following html and body rule sets are required only if using a % width or height*/
/*html {
width: 100%;
height: 100%;
}*/
body {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0 20px 0 20px;
  text-align: center;
  background: white;
}
.scrollingtable {
  box-sizing: border-box;
  display: inline-block;
  vertical-align: middle;
  overflow: hidden;
  width: auto; /*if you want a fixed width, set it here, else set to auto*/
  min-width: 0/*100%*/; /*if you want a % width, set it here, else set to 0*/
  height: 188px/*100%*/; /*set table height here; can be fixed value or %*/
  min-height: 0/*104px*/; /*if using % height, make this large enough to fit scrollbar arrows + caption + thead*/
  font-family: Verdana, Tahoma, sans-serif;
  font-size: 15px;
  line-height: 20px;
  padding: 20px 0 20px 0; /*need enough padding to make room for caption*/
  text-align: left;
}
.scrollingtable * {box-sizing: border-box;}
.scrollingtable > div {
  position: relative;
  border-top: 1px solid black;
  height: 100%;
  padding-top: 20px; /*this determines column header height*/
}
.scrollingtable > div:before {
  top: 0;
  background: cornflowerblue; /*header row background color*/
}
.scrollingtable > div:before,
.scrollingtable > div > div:after {
  content: "";
  position: absolute;
  z-index: -1;
  width: 100%;
  height: 100%;
  left: 0;
}
.scrollingtable > div > div {
  min-height: 0/*43px*/; /*if using % height, make this large enough to fit scrollbar arrows*/
  max-height: 100%;
  overflow: scroll/*auto*/; /*set to auto if using fixed or % width; else scroll*/
  overflow-x: hidden;
  border: 1px solid black; /*border around table body*/
}
.scrollingtable > div > div:after {background: white;} /*match page background color*/
.scrollingtable > div > div > table {
  width: 100%;
  border-spacing: 0;
  margin-top: -20px; /*inverse of column header height*/
  /*margin-right: 17px;*/ /*uncomment if using % width*/
}
.scrollingtable > div > div > table > caption {
  position: absolute;
  top: -20px; /*inverse of caption height*/
  margin-top: -1px; /*inverse of border-width*/
  width: 100%;
  font-weight: bold;
  text-align: center;
}
.scrollingtable > div > div > table > * > tr > * {padding: 0;}
.scrollingtable > div > div > table > thead {
  vertical-align: bottom;
  white-space: nowrap;
  text-align: center;
}
.scrollingtable > div > div > table > thead > tr > * > div {
  display: inline-block;
  padding: 0 6px 0 6px; /*header cell padding*/
}
.scrollingtable > div > div > table > thead > tr > :first-child:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  height: 20px; /*match column header height*/
  border-left: 1px solid black; /*leftmost header border*/
}
.scrollingtable > div > div > table > thead > tr > * > div[label]:before,
.scrollingtable > div > div > table > thead > tr > * > div > div:first-child,
.scrollingtable > div > div > table > thead > tr > * + :before {
  position: absolute;
  top: 0;
  white-space: pre-wrap;
  color: white; /*header row font color*/
}
.scrollingtable > div > div > table > thead > tr > * > div[label]:before,
.scrollingtable > div > div > table > thead > tr > * > div[label]:after {content: attr(label);}
.scrollingtable > div > div > table > thead > tr > * + :before {
  content: "";
  display: block;
  min-height: 20px; /*match column header height*/
  padding-top: 1px;
  border-left: 1px solid black; /*borders between header cells*/
}
.scrollingtable .scrollbarhead {float: right;}
.scrollingtable .scrollbarhead:before {
  position: absolute;
  width: 100px;
  top: -1px; /*inverse border-width*/
  background: white; /*match page background color*/
}
.scrollingtable > div > div > table > tbody > tr:after {
  content: "";
  display: table-cell;
  position: relative;
  padding: 0;
  border-top: 1px solid black;
  top: -1px; /*inverse of border width*/
}
.scrollingtable > div > div > table > tbody {vertical-align: top;}
.scrollingtable > div > div > table > tbody > tr {background: white;}
.scrollingtable > div > div > table > tbody > tr > * {
  border-bottom: 1px solid black;
  padding: 0 6px 0 6px;
  height: 20px; /*match column header height*/
}
.scrollingtable > div > div > table > tbody:last-of-type > tr:last-child > * {border-bottom: none;}
.scrollingtable > div > div > table > tbody > tr:nth-child(even) {background: gainsboro;} /*alternate row color*/
.scrollingtable > div > div > table > tbody > tr > * + * {border-left: 1px solid black;} /*borders between body cells*/
<div class="scrollingtable">
  <div>
    <div>
      <table>
        <caption>Top Caption</caption>
        <thead>
          <tr>
            <th><div label="Column 1"></div></th>
            <th><div label="Column 2"></div></th>
            <th><div label="Column 3"></div></th>
            <th>
              <!--more versatile way of doing column label; requires 2 identical copies of label-->
              <div><div>Column 4</div><div>Column 4</div></div>
            </th>
            <th class="scrollbarhead"/> <!--ALWAYS ADD THIS EXTRA CELL AT END OF HEADER ROW-->
          </tr>
        </thead>
        <tbody>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
        </tbody>
      </table>
    </div>
    Faux bottom caption
  </div>
</div>

<!--[if lte IE 9]><style>.scrollingtable > div > div > table {margin-right: 17px;}</style><![endif]-->

DoctorDestructo
fonte
trabalho incrível. No entanto, tenho uma tabela com 15 colunas e agora também não consigo conter a tabela na página sem uma barra de rolagem horizontal. Eu tentei ajustar seu css, seu css lindamente codificado, para acomodar colunas com largura mais dinâmica, mas nada que eu mudei além da largura da tabela faz diferença. Se eu alterar a largura da tabela para 100%, a tabela renderizará na largura da tabela, mas como as larguras das colunas não serão quebradas, ainda não consigo ver todas as 15 colunas de dados. Eu quase tenho uma mesa de rolagem que parece muito kewl, então qualquer ajuda apreciada.
Nanker
oh espere um segundo, sem barra de rolagem horizontal, a mesa apenas corta.
Nanker
@nanker Se você precisa de rolagem horizontal e deseja usar um pouco de JavaScript, deve verificar esta resposta . É a melhor maneira de fazer uma tabela de rolagem que conheço. Não havia uma boa maneira de fazer a rolagem horizontal apenas com CSS quando eu postei esta resposta, mas não olhei para isso por um tempo, então não sei o que é possível agora.
DoctorDestructo
Otimo trabalho. Você poderia comentar sobre como ajustar várias linhas de cabeçalho? Simplesmente repetir a <tr><th></th>..</tr>construção claramente não funciona. Obrigado.
David I. McIntosh
@ DavidI.McIntosh Um cabeçalho de várias linhas seria complicado usando esta técnica. Adicionar linhas seria fácil, mas não tenho certeza de como você obteria as bordas horizontais entre elas. Você pode querer tentar a solução JavaScript que vinculei no meu comentário anterior, a menos que não possa usar JS por algum motivo.
DoctorDestructo
3

Resolvi esse problema separando meu conteúdo em duas tabelas.

Uma tabela é a linha do cabeçalho.

Os segundos também são <table>marcados, mas envolvidos por <div>altura estática e rolagem de estouro.

Zvi
fonte
1

É importante notar que, dependendo do seu objetivo (o meu foi o preenchimento automático dos resultados de uma barra de pesquisa), você pode querer que a altura seja alterável e que a barra de rolagem exista apenas se a altura exceder isso.

Se você quiser, substitua height: x;por max-height: x;e overflow:scrollpor overflow:auto.

Além disso, você pode usar overflow-xe overflow-yse quiser e, obviamente, a mesma coisa funciona horizontalmente comwidth : x;

Ben
fonte
0

Se você chegar ao ponto em que todas as soluções mencionadas não funcionam (como aconteceu para mim), faça o seguinte:

  • Crie duas tabelas. Um para o cabeçalho e outro para o corpo
  • Dê às duas tabelas diferentes contêineres / divs pai
  • Defina o estilo do div da segunda tabela para permitir a rolagem vertical de seu conteúdo.

Assim, no seu HTML

<div class="table-header-class">
    <table>
       <thead>
          <tr>
            <th>Ava</th>
            <th>Alexis</th>
            <th>Mcclure</th>
          </tr>
       </thead>
    </table>
</div>
<div class="table-content-class">
   <table>
       <tbody>
          <tr>
            <td>I am the boss</td>
            <td>No, da-da is not the boss!</td>
            <td>Alexis, I am the boss, right?</td>
          </tr>
       </tbody>
    </table>
</div>

Em seguida, estilize o pai da segunda tabela para permitir a rolagem vertical, em seu CSS

    .table-content-class {
        overflow-y: scroll;    // use auto; or scroll; to allow vertical scrolling; 
        overflow-x: hidden;    // disable horizontal scroll 
    }
Kaká Ruto
fonte
Esta é a mesma implementação da resposta de Zvi um ano antes.
TylerH
0

apenas adicione na mesa

style="overflow-x:auto;"

<table border=1 id="qandatbl" align="center" style="overflow-x:auto;">
    <tr>
    <th class="col1">Question No</th>
    <th class="col2">Option Type</th>
    <th class="col1">Duration</th>
    </tr>

   <tbody>
    <tr>
    <td class='qid'></td>
    <td class="options"></td>
    <td class="duration"></td>
    </tr>
    </tbody>
</table>

style = "overflow-x: auto;" `

Mestre do local de aprendizagem
fonte
A questão era como fazer o corpo de uma tabela rolar verticalmente enquanto o cabeçalho da coluna permanece no lugar.
giraffedata
0

Muito fácil, basta enrolar a mesa em uma div que tem overflow-y:scroll;e overflow-x:scrollpropriedades, e fazer a div tem uma largura e comprimento menor do que a mesa. VAI FUNCIONAR!!!

Convidado
fonte
Ok, vou adicioná-lo na próxima resposta.
Convidado de
Ok, fiz, ainda não sei como indentar o código corretamente no estouro de pilha.
Convidado de
0

O CSS: div{ overflow-y:scroll; overflow-x:scroll; width:20px; height:30px; } table{ width:50px; height:50px; }

Você pode fazer com que a mesa e o DIV ao redor da mesa tenham o tamanho que você quiser, apenas certifique-se de que o DIV seja menor que a mesa. Você DEVE conter a tabela dentro do DIV.

Convidado
fonte