Cabecera fija de tabla y cuerpo desplazable.

Resuelto giulio asked hace 10 años • 29 respuestas

Estoy intentando crear una tabla con encabezado fijo y contenido desplazable usando la tabla bootstrap 3. Lamentablemente, las soluciones que he encontrado no funcionan con bootstrap o estropean el estilo.

Aquí hay una tabla de arranque simple, pero por alguna razón que desconozco, la altura del tbody no es 10px.

height: 10px !important; overflow: scroll;

Ejemplo:

<link rel="stylesheet" type="text/css" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">

<table class="table table-striped">
    <thead>
    <tr>
        <th>Make</th>
        <th>Model</th>
        <th>Color</th>
        <th>Year</th>
    </tr>
    </thead>
    <tbody style="height: 10px !important; overflow: scroll; ">
    <tr>
        <td class="filterable-cell">111 Ford</td>
        <td class="filterable-cell">Escort</td>
        <td class="filterable-cell">Blue</td>
        <td class="filterable-cell">2000</td>
    </tr>
    <tr>
        <td class="filterable-cell">Ford</td>
        <td class="filterable-cell">Escort</td>
        <td class="filterable-cell">Blue</td>
        <td class="filterable-cell">2000</td>
    </tr>
            <tr>
        <td class="filterable-cell">Ford</td>
        <td class="filterable-cell">Escort</td>
        <td class="filterable-cell">Blue</td>
        <td class="filterable-cell">2000</td>
    </tr>
     <tr>
        <td class="filterable-cell">Ford</td>
        <td class="filterable-cell">Escort</td>
        <td class="filterable-cell">Blue</td>
        <td class="filterable-cell">2000</td>
    </tr>
    </tbody>
    
</table>
Expandir fragmento

giulio avatar Jan 17 '14 00:01 giulio
Aceptado

Cabecera de tabla fija: solo CSS

Simplemente position: sticky; top: 0;tus thelementos. (Cromo, FF, Borde)

.tableFixHead          { overflow: auto; height: 100px; }
.tableFixHead thead th { position: sticky; top: 0; z-index: 1; }

/* Just common table stuff. Really. */
table  { border-collapse: collapse; width: 100%; }
th, td { padding: 8px 16px; }
th     { background:#eee; }
<div class="tableFixHead">
  <table>
    <thead>
      <tr><th>TH 1</th><th>TH 2</th></tr>
    </thead>
    <tbody>
      <tr><td>A1</td><td>A2</td></tr>
      <tr><td>B1</td><td>B2</td></tr>
      <tr><td>C1</td><td>C2</td></tr>
      <tr><td>D1</td><td>D2</td></tr>
      <tr><td>E1</td><td>E2</td></tr>
    </tbody>
  </table>
</div>
Expandir fragmento

Para columnas TH verticales adhesivas y TH horizontales (interior TBODY) :

.tableFixHead          { overflow: auto; height: 100px; width: 240px; }
.tableFixHead thead th { position: sticky; top: 0; z-index: 1; }
.tableFixHead tbody th { position: sticky; left: 0; }

Mostrar fragmento de código

Solución del problema de fronteras TH

Dado que borderno se puede pintar correctamente en un THelemento traducido, para recrear y representar "bordes" utilice la box-shadowpropiedad:

/* Borders (if you need them) */
.tableFixHead,
.tableFixHead td {
  box-shadow: inset 1px -1px #000;
}
.tableFixHead th {
  box-shadow: inset 1px 1px #000, 0 1px #000;
}

Mostrar fragmento de código

TH pegajoso no funciona

Asegúrese de que los elementos principales del thelemento " ", al menos hasta tableel elemento (inclusive), no establezcan estilos overflowrelacionados (por ejemplo overflow, overflow-x, overflow-y).

Para obtener más información, consulte stackoverflow.com/ ¿ Por qué la 'posición: pegajosa' no funciona?


Cabecera de tabla fija: usando JavaScript

Para navegadores antiguos , puedes usar un poco de JS y traducir los thelementos.

// Fix table head example:

function tableFixHead(evt) {
  const el = evt.currentTarget,
    sT = el.scrollTop;
  el.querySelectorAll("thead th").forEach(th =>
    th.style.transform = `translateY(${sT}px)`
  );
}

document.querySelectorAll(".tableFixHead").forEach(el =>
  el.addEventListener("scroll", tableFixHead)
);
.tableFixHead {
  overflow-y: auto;
  height: 100px;
}


/* Just common table stuff. */

table {
  border-collapse: collapse;
  width: 100%;
}

th,
td {
  padding: 8px 16px;
}

th {
  background: #eee;
}
<div class="tableFixHead">
  <table>
    <thead>
      <tr><th>TH 1</th><th>TH 2</th></tr>
    </thead>
    <tbody>
      <tr><td>A1</td><td>A2</td></tr>
      <tr><td>B1</td><td>B2</td></tr>
      <tr><td>C1</td><td>C2</td></tr>
      <tr><td>D1</td><td>D2</td></tr>
      <tr><td>E1</td><td>E2</td></tr>
    </tbody>
  </table>
</div>
Expandir fragmento

Roko C. Buljan avatar Dec 21 '2017 11:12 Roko C. Buljan

Para un enfoque CSS puro, necesitaría un contenedor overflow-y: auto;y decidiría cómo ocultar las filas desplazadas/desbordadas:

  1. Superposición con un encabezado adhesivo no transparente ( ), como en la respuestaposition: sticky; top: 0; z-index: 1; de @RokoCBuljan .
  2. Alternar la visibilidad de las filas (configurando tr:afterlas propiedades como se indica a continuación).

Tenga en cuenta que el contenedor puede ser externo <div>, él <table>mismo o una parte de él (p. ej. <tbody>). Para los dos últimos, debes configurarlos display: block;de manera tan efectiva que se traten como divs.

Vea a continuación una solución modificada de @giulio:

:root {
  --height-height: 150px;
  /* cell width has to reserve some space for scrolling. Hence the sum < 100% */
  --cell-width: 85px;
}

.header-fixed {
  width: 200px;
}

/* Treat all as divs */
.header-fixed > thead,
.header-fixed > tbody,
.header-fixed > thead > tr,
.header-fixed > tbody > tr,
.header-fixed > thead > tr > th,
.header-fixed > tbody > tr > td {
  display: block;
}

/* Prevent header to wrap */
.header-fixed > thead > tr > th {
  white-space: nowrap;
  background-color: lightgrey;
}

.header-fixed > tbody > tr:after,
.header-fixed > thead > tr:after {
  content: ' ';
  display: block;
  visibility: hidden;
  clear: both;
}

.header-fixed > tbody {
  overflow-y: auto;
  height: var(--height-height);
}

.header-fixed > tbody > tr > td,
.header-fixed > thead > tr > th {
  width: var(--cell-width);
  border: thin solid grey;
  float: left;
}
<table class="header-fixed">
 <thead>
   <tr> <th>Header 1</th> <th>Header 2</th> </tr>
 </thead>
 <tbody>
   <tr> <td>cell 11</td> <td>cell 12</td> </tr>
   <tr> <td>cell 21</td> <td>cell 22</td> </tr>
   <tr> <td>cell 31</td> <td>cell 32</td> </tr>
   <tr> <td>cell 41</td> <td>cell 42</td> </tr>
   <tr> <td>cell 51</td> <td>cell 52</td> </tr>
   <tr> <td>cell 61</td> <td>cell 62</td> </tr>
   <tr> <td>cell 71</td> <td>cell 72</td> </tr>
   <tr> <td>cell 81</td> <td>cell 82</td> </tr>
   <tr> <td>cell 91</td> <td>cell 92</td> </tr>
 </tbody>
</table>
Expandir fragmento

Nota: Si tiene >2 columnas, debe modificar la var(--cell-width)variable en consecuencia.

Alex Klaus avatar Apr 04 '2014 06:04 Alex Klaus

Aquí está la solución de trabajo:

table {
    width: 100%;
}

thead, tbody, tr, td, th { display: block; }

tr:after {
    content: ' ';
    display: block;
    visibility: hidden;
    clear: both;
}

thead th {
    height: 30px;

    /*text-align: left;*/
}

tbody {
    height: 120px;
    overflow-y: auto;
}

thead {
    /* fallback */
}


tbody td, thead th {
    width: 19.2%;
    float: left;
}
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"/>

<table class="table table-striped">
    <thead>
        <tr>
            <th>Make</th>
            <th>Model</th>
            <th>Color</th>
            <th>Year</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td class="filterable-cell">Ford</td>
            <td class="filterable-cell">Escort</td>
            <td class="filterable-cell">Blue</td>
            <td class="filterable-cell">2000</td>
        </tr>
        <tr>
            <td class="filterable-cell">Ford</td>
            <td class="filterable-cell">Escort</td>
            <td class="filterable-cell">Blue</td>
            <td class="filterable-cell">2000</td>
        </tr>
        <tr>
            <td class="filterable-cell">Ford</td>
            <td class="filterable-cell">Escort</td>
            <td class="filterable-cell">Blue</td>
            <td class="filterable-cell">2000</td>
        </tr>
        <tr>
            <td class="filterable-cell">Ford</td>
            <td class="filterable-cell">Escort</td>
            <td class="filterable-cell">Blue</td>
            <td class="filterable-cell">2000</td>
        </tr>
    </tbody>
</table>
Expandir fragmento

Enlace a jsfiddle

giulio avatar Jan 16 '2014 23:01 giulio

Actualizar

Para una biblioteca más nueva y aún mantenida, pruebe con jquery.floatThead (como lo menciona Bob Jordan en el comentario) .

Antigua respuesta

Esta es una respuesta muy antigua, la biblioteca que se menciona a continuación ya no se mantiene.

¡Estoy usando StickyTableHeaders en GitHub y funciona de maravilla!

Sin embargo, tuve que agregar este CSS para que el encabezado no fuera transparente.

table#stickyHeader thead {
  border-top: none;
  border-bottom: none;
  background-color: #FFF;
}
Rosdi Kasim avatar Dec 17 '2014 17:12 Rosdi Kasim

Con diferencia, la mejor solución que he visto es solo CSS, con buena compatibilidad con varios navegadores y sin problemas de alineación es esta solución de codingrabbithole.

table {
  width: 100%;
}
thead, tbody tr {
  display: table;
  width: 100%;
  table-layout: fixed;
}
tbody {
  display: block;
  overflow-y: auto;
  table-layout: fixed;
  max-height: 200px;
}
St John avatar Aug 14 '2020 12:08 St John