Tabla HTML con 100% de ancho, con desplazamiento vertical dentro del cuerpo

423

¿Cómo puedo establecer un <table>ancho del 100% y poner solo dentro del <tbody>desplazamiento vertical para cierta altura?

desplazamiento vertical dentro del cuerpo

table {
    width: 100%;
    display:block;
}
thead {
    display: inline-block;
    width: 100%;
    height: 20px;
}
tbody {
    height: 200px;
    display: inline-block;
    width: 100%;
    overflow: auto;
}
  
<table>
  <thead>
    <tr>
    	<th>Head 1</th>
    	<th>Head 2</th>
    	<th>Head 3</th>
    	<th>Head 4</th>
    	<th>Head 5</th>
    </tr>
  </thead>
  <tbody>
    <tr>
    	<td>Content 1</td>
    	<td>Content 2</td>
    	<td>Content 3</td>
    	<td>Content 4</td>
    	<td>Content 5</td>
    </tr>
  </tbody>
</table>

Quiero evitar agregar algunos div adicionales, todo lo que quiero es una tabla simple como esta y cuando trato de cambiar la visualización table-layout, positiony muchas cosas más en la tabla CSS no funcionan bien con un ancho del 100% solo con un ancho fijo en px.

Marko S
fuente
No estoy realmente seguro de lo que quieres lograr. mira esto: jsfiddle.net/CrSpu y di cómo quieres que se comporte
x4rf41
2
lo sé pero mira ... th y td no se muestran en todo su ancho ... postimg.org/image/mgd630y61
Marko S
Relacionado: stackoverflow.com/questions/1019938/…
Christophe Roussy

Respuestas:

675

Para hacer que el <tbody>elemento se pueda desplazar, necesitamos cambiar la forma en que se muestra en la página, es decir, usarlo display: block;para mostrarlo como un elemento de nivel de bloque.

Como cambiamos la displaypropiedad de tbody, también debemos cambiar esa propiedad para el theadelemento para evitar que se rompa el diseño de la tabla.

Entonces tenemos:

thead, tbody { display: block; }

tbody {
    height: 100px;       /* Just for the demo          */
    overflow-y: auto;    /* Trigger vertical scroll    */
    overflow-x: hidden;  /* Hide the horizontal scroll */
}

Los navegadores web muestran los elementos theady tbodycomo grupo de filas ( table-header-groupy table-row-group) de forma predeterminada.

Una vez que cambiamos eso, los trelementos internos no llenan todo el espacio de su contenedor.

Para solucionarlo, debemos calcular el ancho de las tbodycolumnas y aplicar el valor correspondiente a las theadcolumnas a través de JavaScript.

Columnas de ancho automático

Aquí está la versión jQuery de la lógica anterior:

// Change the selector if needed
var $table = $('table'),
    $bodyCells = $table.find('tbody tr:first').children(),
    colWidth;

// Get the tbody columns width array
colWidth = $bodyCells.map(function() {
    return $(this).width();
}).get();

// Set the width of thead columns
$table.find('thead tr').children().each(function(i, v) {
    $(v).width(colWidth[i]);
});    

Y aquí está la salida (en Windows 7 Chrome 32) :

desplazamiento vertical dentro del cuerpo

DEMO DE TRABAJO .

Tabla de ancho completo, columnas de ancho relativo

Como lo necesitaba el Cartel original, podríamos expandirlo tableal 100% de widthsu contenedor, y luego usar un relativo ( Porcentaje ) widthpara cada columna de la tabla.

table {
    width: 100%; /* Optional */
}

tbody td, thead th {
    width: 20%;  /* Optional */
}

Dado que la tabla tiene un diseño fluido , deberíamos ajustar el ancho de las theadcolumnas cuando el contenedor cambia de tamaño.

Por lo tanto, deberíamos establecer el ancho de las columnas una vez que la ventana cambia de tamaño:

// Adjust the width of thead cells when *window* resizes
$(window).resize(function() {
    /* Same as before */ 
}).resize(); // Trigger the resize handler once the script runs

El resultado sería:

Mesa fluida con desplazamiento vertical dentro del cuerpo

DEMO DE TRABAJO .


Soporte del navegador y alternativas

He probado los dos métodos anteriores en Windows 7 a través de las nuevas versiones de los principales navegadores web (incluido IE10 +) y funcionó.

Sin embargo, no funciona correctamente en IE9 y versiones posteriores.

Eso es porque en un diseño de tabla , todos los elementos deben seguir las mismas propiedades estructurales.

Al usar display: block;para los elementos <thead>y <tbody>, hemos roto la estructura de la tabla.

Diseño de rediseño a través de JavaScript

Un enfoque es rediseñar el diseño de tabla (completo). Usar JavaScript para crear un nuevo diseño sobre la marcha y manejar y / o ajustar los anchos / alturas de las celdas dinámicamente.

Por ejemplo, eche un vistazo a los siguientes ejemplos:

Mesas de anidamiento

Este enfoque utiliza dos tablas anidadas con un div que contiene. La primera tabletiene solo una celda que tiene un div, y la segunda tabla se coloca dentro de ese divelemento.

Consulte las tablas de desplazamiento vertical en CSS Play .

Esto funciona en la mayoría de los navegadores web. También podemos hacer la lógica anterior de forma dinámica a través de JavaScript.

Tabla con encabezado fijo en desplazamiento

Dado que el propósito de agregar una barra de desplazamiento vertical al <tbody>mostrar el encabezado de la tabla en la parte superior de cada fila, podríamos colocar el theadelemento para que permanezca fixeden la parte superior de la pantalla.

Aquí hay una demostración de trabajo de este enfoque realizado por Julien .
Tiene un soporte de navegador web prometedor.

Y aquí una implementación CSS pura por Willem Van Bockstal .


La solución CSS pura

Aquí está la vieja respuesta. Por supuesto, agregué un nuevo método y perfeccioné las declaraciones CSS.

Mesa con ancho fijo

En este caso, tabledebería tener un valor fijo width (incluida la suma de los anchos de las columnas y el ancho de la barra de desplazamiento vertical) .

Cada columna debe tener una determinada anchura y la última columna del theadelemento necesita una mayor anchura que es igual a la de los demás ancho + el ancho de la barra de desplazamiento vertical.

Por lo tanto, el CSS sería:

table {
    width: 716px; /* 140px * 5 column + 16px scrollbar width */
    border-spacing: 0;
}

tbody, thead tr { display: block; }

tbody {
    height: 100px;
    overflow-y: auto;
    overflow-x: hidden;
}

tbody td, thead th {
    width: 140px;
}

thead th:last-child {
    width: 156px; /* 140px + 16px scrollbar width */
}

Aquí está la salida:

Mesa con ancho fijo

DEMO DE TRABAJO .

Mesa con 100% de ancho

En este enfoque, tabletiene un ancho de 100%y para cada thy td, el valor de la widthpropiedad debe ser menor que 100% / number of cols.

Además, tenemos que reducir el ancho de theadcomo el valor de la anchura de la barra de desplazamiento vertical.

Para hacer eso, necesitamos usar la calc()función CSS3 , de la siguiente manera:

table {
    width: 100%;
    border-spacing: 0;
}

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

thead tr {
    /* fallback */
    width: 97%;
    /* minus scroll bar width */
    width: -webkit-calc(100% - 16px);
    width:    -moz-calc(100% - 16px);
    width:         calc(100% - 16px);
}

tr:after {  /* clearing float */
    content: ' ';
    display: block;
    visibility: hidden;
    clear: both;
}

tbody {
    height: 100px;
    overflow-y: auto;
    overflow-x: hidden;
}

tbody td, thead th {
    width: 19%;  /* 19% is less than (100% / 5 cols) = 20% */
    float: left;
}

Aquí está la demostración en línea .

Nota: este enfoque fallará si el contenido de cada columna rompe la línea, es decir, el contenido de cada celda debe ser lo suficientemente corto .


A continuación, hay dos ejemplos simples de solución CSS pura que creé en el momento en que respondí esta pregunta.

Aquí está la jsFiddle Demo v2 .

Versión anterior: jsFiddle Demo v1

Hashem Qolami
fuente
17
Con display: blockusted suelta propiedades de mesa como el ancho de la columna compartida entre la culata en T y tbody. Sé que ha solucionado esto configurando, width: 19.2%pero en caso de que no sepamos el ancho de cada columna de antemano, esto no funcionará.
samb
10
Este código parece suponer que las células del cuerpo siempre serán más anchas que las celdas del encabezado.
Adam Donahue
2
No funciona cuando height: 100%(cuando quiere que la tabla se expanda al final de la página).
AlikElzin-kilaka
2
Esto también funciona fantásticamente con las ng-repeattablas AngularJS . No estoy seguro de por qué hay todas esas bibliotecas con encabezados de tabla fijos y qué no cuando existe esta solución.
chakeda
2
Puede mejorar esto un poco más con la box-sizingpropiedad para que tener bordes de dos grosores diferentes no altere la alineación de la columna.
Ricca
89

En la siguiente solución, la tabla ocupa el 100% del contenedor principal, no se requieren tamaños absolutos. Es puro CSS, se utiliza diseño flexible.

Así es como se ve: ingrese la descripción de la imagen aquí

Posibles desventajas:

  • la barra de desplazamiento vertical siempre está visible, independientemente de si es necesaria;
  • el diseño de la tabla es fijo: las columnas no cambian de tamaño de acuerdo con el ancho del contenido (aún puede establecer el ancho de columna que desee explícitamente);
  • hay un tamaño absoluto: el ancho de la barra de desplazamiento, que es aproximadamente 0.9em para los navegadores que pude verificar.

HTML (acortado):

<div class="table-container">
    <table>
        <thead>
            <tr>
                <th>head1</th>
                <th>head2</th>
                <th>head3</th>
                <th>head4</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>content1</td>
                <td>content2</td>
                <td>content3</td>
                <td>content4</td>
            </tr>
            <tr>
                <td>content1</td>
                <td>content2</td>
                <td>content3</td>
                <td>content4</td>
            </tr>
            ...
        </tbody>
    </table>
</div>

CSS, con algunas decoraciones omitidas por claridad:

.table-container {
    height: 10em;
}
table {
    display: flex;
    flex-flow: column;
    height: 100%;
    width: 100%;
}
table thead {
    /* head takes the height it requires, 
    and it's not scaled when table is resized */
    flex: 0 0 auto;
    width: calc(100% - 0.9em);
}
table tbody {
    /* body takes all the remaining available space */
    flex: 1 1 auto;
    display: block;
    overflow-y: scroll;
}
table tbody tr {
    width: 100%;
}
table thead, table tbody tr {
    display: table;
    table-layout: fixed;
}

código completo en jsfiddle

Mismo código en MENOS para que pueda mezclarlo en:

.table-scrollable() {
  @scrollbar-width: 0.9em;
  display: flex;
  flex-flow: column;

  thead,
  tbody tr {
    display: table;
    table-layout: fixed;
  }

  thead {
    flex: 0 0 auto;
    width: ~"calc(100% - @{scrollbar-width})";
  }

  tbody {
    display: block;
    flex: 1 1 auto;
    overflow-y: scroll;

    tr {
      width: 100%;
    }
  }
}
tsayen
fuente
2
Gracias por la solucion! Hubo un pequeño error ... estableciste el ancho para el dos veces, y descubrí que restando 1.05em del ancho se alinea un poco mejor: jsfiddle.net/xuvsncr2/170
TigerBear
1
¿Qué pasa con el número de contenido del personaje? se complica cuando agrega más caracteres o palabras dentro de las celdas de fila
Limon
Creo que establecer alguna política de envoltura adecuada tddebería ayudar
tsayen
¿Alguna solución como esta pero dejando de lado la necesidad del 100% de ancho?
Alexandre Pereira Nunes
2
@tsayen ¿Cómo evitas que se arrugue y se superponga cuando cambias el tamaño de la ventana?
clearshot66
31

En los navegadores modernos, simplemente puede usar css:

th {
  position: sticky;
  top: 0;
  z-index: 2;
}
Gauss
fuente
8
Este encantamiento está incompleto ... ¿Te importa publicar un ejemplo, o al menos elaborar?
Liam
funciona bien, pero solo se aplica a th. Si establecemos la posición pegajosa en la cabeza, entonces no funciona.
Vishal
¡Se corrigió el error que debería agregar al W3C!
sonichy
2
Esta respuesta funciona cuando se envuelve tu <table>con <div>lo que tiene overflow-y: auto;y algo max-height. Por ejemplo:<div style="overflow-y: auto; max-height: 400px;"><table>...</table></div>
Minwork
A partir de 2020, esta será la respuesta seleccionada (junto con la actualización de @Minwork)
Christophe Vidal
18

Estoy usando display:blockpara theady tbody. Por eso, el ancho de las theadcolumnas es diferente del ancho de las tbodycolumnas.

table {
    margin:0 auto; 
    border-collapse:collapse;
}
thead {
    background:#CCCCCC;
    display:block
}
tbody {
    height:10em;overflow-y:scroll;
    display:block
}

Para solucionar esto, uso un jQuerycódigo pequeño pero solo se puede hacer JavaScript.

var colNumber=3 //number of table columns    

for (var i=0; i<colNumber; i++) {
  var thWidth=$("#myTable").find("th:eq("+i+")").width();
  var tdWidth=$("#myTable").find("td:eq("+i+")").width();      
  if (thWidth<tdWidth)                    
      $("#myTable").find("th:eq("+i+")").width(tdWidth);
  else
      $("#myTable").find("td:eq("+i+")").width(thWidth);           
}  

Aquí está mi demo de trabajo: http://jsfiddle.net/gavroche/N7LEF/

No funciona en IE 8

gavroche
fuente
Esta es la solución mejor / más simple que he encontrado que permite anchos de columna no fijos (por ejemplo, control .NET DataGrid). Para "producción", la colNumbervariable podría ser reemplazada por un código que itera a través de las celdas reales encontradas en su lugar, y tenga en cuenta que no funciona correctamente si hay alguna colspans (también podría mejorarse en el código, si es necesario, pero poco probable en el tipo de tabla que probablemente desee esta función de desplazamiento).
JonBrave
Esto funciona (de una manera), pero no funciona cuando el tamaño de la ventana es más pequeño que la tabla (ya que ignora el ancho de la barra de desplazamiento).
Gone Coding
Sí, el encabezado y las celdas ya no coinciden si el ancho de la tabla está confinado a un ancho establecido
Craig
mejor respuesta aquí, la más simple también
Charles Okwuagwu, el
18

Solo CSS

para Chrome, Firefox, Edge (y otros navegadores de hoja perenne )

Simplemente position: sticky; top: 0;tus thelementos:

/* Fix table head */
.tableFixHead    { overflow-y: auto; height: 100px; }
.tableFixHead th { position: sticky; top: 0; }

/* 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>

PD: si necesita bordes para elementos TH th {box-shadow: 1px 1px 0 #000; border-top: 0;}, ayudará (ya que los bordes predeterminados no están pintados correctamente en el desplazamiento).

Para una variante de lo anterior que usa solo un poco de JS para acomodar IE11, vea esta respuesta https://stackoverflow.com/a/47923622/383904

Roko C. Buljan
fuente
Si tiene bordes para los elementos, el uso de "border-collapse: collapse" pegará el borde al cuerpo en lugar del encabezado. Para evitar este problema, debe usar "border-collapse: separe". Ver stackoverflow.com/a/53559396
mrod
@mrod cuando usas separateestás agregando aceite al fuego. jsfiddle.net/RokoCB/o0zL4xyw y vea una solución AQUÍ: agregue bordes a TH fijo - Soy bienvenido para sugerencias de OFC si me perdí algo.
Roko C. Buljan
11

Cree dos tablas una tras otra, coloque la segunda tabla en un div de altura fija y configure la propiedad de desbordamiento en auto. También mantenga vacíos todos los td's dentro de la pantalla en la segunda tabla.

<div>
    <table>
        <thead>
            <tr>
                <th>Head 1</th>
                <th>Head 2</th>
                <th>Head 3</th>
                <th>Head 4</th>
                <th>Head 5</th>
            </tr>
        </thead>
    </table>
</div>

<div style="max-height:500px;overflow:auto;">
    <table>
        <thead>
            <tr>
                <th></th>
                <th></th>
                <th></th>
                <th></th>
                <th></th>
            </tr>
        </thead>
        <tbody>
        <tr>
            <td>Content 1</td>
            <td>Content 2</td>
            <td>Content 3</td>
            <td>Content 4</td>
            <td>Content 5</td>
        </tr>
        </tbody>
    </table>    
</div>
Sushil Kumar
fuente
8
En este caso, las columnas de la segunda tabla no pueden seguir el ancho de la primera tabla.
kat1330
2
¡No está bien! Pierde la sincronización de ancho para columnas en dos tablas.
Zafar
1
para completar esta solución, necesitamos agregar el script @Hashem Qolami ( describir arriba ) para sincronizar el ancho de las columnas del encabezado
Elhay Avichzer
6

Finalmente lo entendí bien con CSS puro siguiendo estas instrucciones:

http://tjvantoll.com/2012/11/10/creating-cross-browser-scrollable-tbody/

El primer paso es configurar el <tbody>bloque de visualización: para que se pueda aplicar un desbordamiento y altura. A partir de ahí, las filas <thead>deben establecerse en position: relative y display: block para que se asienten sobre el ahora desplazable <tbody>.

tbody, thead { display: block; overflow-y: auto; }

Debido a que <thead>está relativamente posicionada, cada celda de la tabla necesita un ancho explícito

td:nth-child(1), th:nth-child(1) { width: 100px; }
td:nth-child(2), th:nth-child(2) { width: 100px; }
td:nth-child(3), th:nth-child(3) { width: 100px; }

Pero desafortunadamente eso no es suficiente. Cuando una barra de desplazamiento está presente, los navegadores le asignan espacio, por lo tanto, el <tbody>final tiene menos espacio disponible que el <thead>. Observe la ligera desalineación que esto crea ...

La única solución que se me ocurrió fue establecer un ancho mínimo en todas las columnas, excepto en la última.

td:nth-child(1), th:nth-child(1) { min-width: 100px; }
td:nth-child(2), th:nth-child(2) { min-width: 100px; }
td:nth-child(3), th:nth-child(3) { width: 100px; }

Ejemplo de codepen completo a continuación:

CSS:

.fixed_headers {
  width: 750px;
  table-layout: fixed;
  border-collapse: collapse;
}
.fixed_headers th {
  text-decoration: underline;
}
.fixed_headers th,
.fixed_headers td {
  padding: 5px;
  text-align: left;
}
.fixed_headers td:nth-child(1),
.fixed_headers th:nth-child(1) {
  min-width: 200px;
}
.fixed_headers td:nth-child(2),
.fixed_headers th:nth-child(2) {
  min-width: 200px;
}
.fixed_headers td:nth-child(3),
.fixed_headers th:nth-child(3) {
  width: 350px;
}
.fixed_headers thead {
  background-color: #333333;
  color: #fdfdfd;
}
.fixed_headers thead tr {
  display: block;
  position: relative;
}
.fixed_headers tbody {
  display: block;
  overflow: auto;
  width: 100%;
  height: 300px;
}
.fixed_headers tbody tr:nth-child(even) {
  background-color: #dddddd;
}
.old_ie_wrapper {
  height: 300px;
  width: 750px;
  overflow-x: hidden;
  overflow-y: auto;
}
.old_ie_wrapper tbody {
  height: auto;
}

HTML:

<!-- IE < 10 does not like giving a tbody a height.  The workaround here applies the scrolling to a wrapped <div>. -->
<!--[if lte IE 9]>
<div class="old_ie_wrapper">
<!--<![endif]-->

<table class="fixed_headers">
  <thead>
    <tr>
      <th>Name</th>
      <th>Color</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Apple</td>
      <td>Red</td>
      <td>These are red.</td>
    </tr>
    <tr>
      <td>Pear</td>
      <td>Green</td>
      <td>These are green.</td>
    </tr>
    <tr>
      <td>Grape</td>
      <td>Purple / Green</td>
      <td>These are purple and green.</td>
    </tr>
    <tr>
      <td>Orange</td>
      <td>Orange</td>
      <td>These are orange.</td>
    </tr>
    <tr>
      <td>Banana</td>
      <td>Yellow</td>
      <td>These are yellow.</td>
    </tr>
    <tr>
      <td>Kiwi</td>
      <td>Green</td>
      <td>These are green.</td>
    </tr>
    <tr>
      <td>Plum</td>
      <td>Purple</td>
      <td>These are Purple</td>
    </tr>
    <tr>
      <td>Watermelon</td>
      <td>Red</td>
      <td>These are red.</td>
    </tr>
    <tr>
      <td>Tomato</td>
      <td>Red</td>
      <td>These are red.</td>
    </tr>
    <tr>
      <td>Cherry</td>
      <td>Red</td>
      <td>These are red.</td>
    </tr>
    <tr>
      <td>Cantelope</td>
      <td>Orange</td>
      <td>These are orange inside.</td>
    </tr>
    <tr>
      <td>Honeydew</td>
      <td>Green</td>
      <td>These are green inside.</td>
    </tr>
    <tr>
      <td>Papaya</td>
      <td>Green</td>
      <td>These are green.</td>
    </tr>
    <tr>
      <td>Raspberry</td>
      <td>Red</td>
      <td>These are red.</td>
    </tr>
    <tr>
      <td>Blueberry</td>
      <td>Blue</td>
      <td>These are blue.</td>
    </tr>
    <tr>
      <td>Mango</td>
      <td>Orange</td>
      <td>These are orange.</td>
    </tr>
    <tr>
      <td>Passion Fruit</td>
      <td>Green</td>
      <td>These are green.</td>
    </tr>
  </tbody>
</table>

<!--[if lte IE 9]>
</div>
<!--<![endif]-->

EDITAR: Solución alternativa para el ancho de la tabla al 100% (el anterior es en realidad para el ancho fijo y no respondió la pregunta):

HTML:

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Color</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Apple</td>
      <td>Red</td>
      <td>These are red.</td>
    </tr>
    <tr>
      <td>Pear</td>
      <td>Green</td>
      <td>These are green.</td>
    </tr>
    <tr>
      <td>Grape</td>
      <td>Purple / Green</td>
      <td>These are purple and green.</td>
    </tr>
    <tr>
      <td>Orange</td>
      <td>Orange</td>
      <td>These are orange.</td>
    </tr>
    <tr>
      <td>Banana</td>
      <td>Yellow</td>
      <td>These are yellow.</td>
    </tr>
    <tr>
      <td>Kiwi</td>
      <td>Green</td>
      <td>These are green.</td>
    </tr>
  </tbody>
</table>

CSS:

table {
  width: 100%;
  text-align: left;
  min-width: 610px;
}
tr {
  height: 30px;
  padding-top: 10px
}
tbody { 
  height: 150px; 
  overflow-y: auto;
  overflow-x: hidden;
}
th,td,tr,thead,tbody { display: block; }
td,th { float: left; }
td:nth-child(1),
th:nth-child(1) {
  width: 20%;
}
td:nth-child(2),
th:nth-child(2) {
  width: 20%;
  float: left;
}
td:nth-child(3),
th:nth-child(3) {
  width: 59%;
  float: left;
}
/* some colors */
thead {
  background-color: #333333;
  color: #fdfdfd;
}
table tbody tr:nth-child(even) {
  background-color: #dddddd;
}

Demostración: http://codepen.io/anon/pen/bNJeLO

Mikael Lepistö
fuente
1
La pregunta quería específicamente una tabla de 100% de ancho, que es lo único que no hace el ejemplo al que hizo referencia .
Gone Coding
@TrueBlueAussie Buena captura: D Solución alternativa agregada para 100% de ancho.
Mikael Lepistö
no considera la longitud del contenido de la fila de la celda
Limon
2

Solución CSS para forzar a las columnas a mostrarse correctamente con un cuerpo de 'bloque'

Esta solución todavía requiere que thjQuery calcule y establezca los anchos.

table.scroll tbody,
table.scroll thead { display: block; }

table.scroll tbody {
    overflow-y: auto;
    overflow-x: hidden;
    max-height: 300px;
}

table.scroll tr {
    display: flex;
}

table.scroll tr > td {
    flex-grow: 1;
    flex-basis: 0;
}

Y el Jquery / Javascript

var $table = $('#the_table_element'),
    $bodyCells = $table.find('tbody tr:first').children(),
    colWidth;

$table.addClass('scroll');

// Adjust the width of thead cells when window resizes
$(window).resize(function () {

    // Get the tbody columns width array
    colWidth = $bodyCells.map(function () {
        return $(this).width();
    }).get();

    // Set the width of thead columns
    $table.find('thead tr').children().each(function (i, v) {
        $(v).width(colWidth[i]);
    });

}).resize(); // Trigger resize handler
Emmanuel
fuente
@Craig en 2019, está bien no preocuparse por IE en absoluto.
Automagisch
2

prueba a continuación, muy simple, fácil de implementar

A continuación se muestra el enlace jsfiddle

http://jsfiddle.net/v2t2k8ke/2/

HTML:

<table border='1' id='tbl_cnt'>
<thead><tr></tr></thead><tbody></tbody>

CSS:

 #tbl_cnt{
 border-collapse: collapse; width: 100%;word-break:break-all;
 }
 #tbl_cnt thead, #tbl_cnt tbody{
 display: block;
 }
 #tbl_cnt thead tr{
 background-color: #8C8787; text-align: center;width:100%;display:block;
 }
 #tbl_cnt tbody {
 height: 100px;overflow-y: auto;overflow-x: hidden;
 }

Jquery:

 var data = [
    {
    "status":"moving","vehno":"tr544","loc":"bng","dri":"ttt"
    }, {
    "status":"stop","vehno":"tr54","loc":"che", "dri":"ttt"
    },{    "status":"idle","vehno":"yy5499999999999994","loc":"bng","dri":"ttt"
    },{
    "status":"moving","vehno":"tr544","loc":"bng", "dri":"ttt"
    }, {
    "status":"stop","vehno":"tr54","loc":"che","dri":"ttt"
    },{
    "status":"idle","vehno":"yy544","loc":"bng","dri":"ttt"
    }
    ];
   var sth = '';
   $.each(data[0], function (key, value) {
     sth += '<td>' + key + '</td>';
   });
   var stb = '';        
   $.each(data, function (key, value) {
       stb += '<tr>';
       $.each(value, function (key, value) {
       stb += '<td>' + value + '</td>';
       });
       stb += '</tr>';
    });
      $('#tbl_cnt thead tr').append(sth);
      $('#tbl_cnt tbody').append(stb);
      setTimeout(function () {
      var col_cnt=0 
      $.each(data[0], function (key, value) {col_cnt++;});    
      $('#tbl_cnt thead tr').css('width', ($("#tbl_cnt tbody") [0].scrollWidth)+ 'px');
      $('#tbl_cnt thead tr td,#tbl_cnt tbody tr td').css('width',  ($('#tbl_cnt thead tr ').width()/Number(col_cnt)) + 'px');}, 100)
Nandha
fuente
2
Esta solución no hace frente a que la ventana sea más estrecha que el ancho de la tabla. Debería permitir el desplazamiento horizontal cuando eso suceda. Además, los encabezados no se alinean exactamente con las celdas de datos (Chrome).
Ido codificación
No funciona hoy en día
MrHIDEn
2

Agregando un ancho fijo a td, th después de hacer que tbody & thead display block funcione perfectamente y también podemos usar el complemento slimscroll para hacer que la barra de desplazamiento sea hermosa.

ingrese la descripción de la imagen aquí

<!DOCTYPE html>
<html>

<head>
    <title> Scrollable table </title>
    <style>
        body {
            font-family: sans-serif;
            font-size: 0.9em;
        }
        table {
            border-collapse: collapse;
            border-bottom: 1px solid #ddd;
        }
        thead {
            background-color: #333;
            color: #fff;
        }
        thead,tbody {
            display: block;
        }
        th,td {
            padding: 8px 10px;
            border: 1px solid #ddd;
            width: 117px;
            box-sizing: border-box;
        }
        tbody {
            height: 160px;
            overflow-y: scroll
        }
    </style>
</head>

<body>

    <table class="example-table">
        <thead>
            <tr>
                <th> Header 1 </th>
                <th> Header 2 </th>
                <th> Header 3 </th>
                <th> Header 4 </th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td> Row 1- Col 1 </td>
                <td> Row 1- Col 2 </td>
                <td> Row 1- Col 3 </td>
                <td> Row 1- Col 4 </td>
            </tr>
            <tr>
                <td> Row 2- Col 1 </td>
                <td> Row 2- Col 2 </td>
                <td> Row 2- Col 3 </td>
                <td> Row 2- Col 4 </td>
            </tr>
            <tr>
                <td> Row 3- Col 1 </td>
                <td> Row 3- Col 2 </td>
                <td> Row 3- Col 3 </td>
                <td> Row 3- Col 4 </td>
            </tr>
            <tr>
                <td> Row 4- Col 1 </td>
                <td> Row 4- Col 2 </td>
                <td> Row 4- Col 3 </td>
                <td> Row 4- Col 4 </td>
            </tr>
            <tr>
                <td> Row 5- Col 1 </td>
                <td> Row 5- Col 2 </td>
                <td> Row 5- Col 3 </td>
                <td> Row 5- Col 4 </td>
            </tr>
            <tr>
                <td> Row 6- Col 1 </td>
                <td> Row 6- Col 2 </td>
                <td> Row 6- Col 3 </td>
                <td> Row 6- Col 4 </td>
            </tr>
            <tr>
                <td> Row 7- Col 1 </td>
                <td> Row 7- Col 2 </td>
                <td> Row 7- Col 3 </td>
                <td> Row 7- Col 4 </td>
            </tr>
            <tr>
                <td> Row 8- Col 1 </td>
                <td> Row 8- Col 2 </td>
                <td> Row 8- Col 3 </td>
                <td> Row 8- Col 4 </td>
            </tr>
            <tr>
                <td> Row 9- Col 1 </td>
                <td> Row 9- Col 2 </td>
                <td> Row 9- Col 3 </td>
                <td> Row 9- Col 4 </td>
            </tr>
            <tr>
                <td> Row 10- Col 1 </td>
                <td> Row 10- Col 2 </td>
                <td> Row 10- Col 3 </td>
                <td> Row 10- Col 4 </td>
            </tr>
            <tr>
                <td> Row 11- Col 1 </td>
                <td> Row 11- Col 2 </td>
                <td> Row 11- Col 3 </td>
                <td> Row 11- Col 4 </td>
            </tr>
            <tr>
                <td> Row 12- Col 1 </td>
                <td> Row 12- Col 2 </td>
                <td> Row 12- Col 3 </td>
                <td> Row 12- Col 4 </td>
            </tr>
            <tr>
                <td> Row 13- Col 1 </td>
                <td> Row 13- Col 2 </td>
                <td> Row 13- Col 3 </td>
                <td> Row 13- Col 4 </td>
            </tr>
            <tr>
                <td> Row 14- Col 1 </td>
                <td> Row 14- Col 2 </td>
                <td> Row 14- Col 3 </td>
                <td> Row 14- Col 4 </td>
            </tr>
            <tr>
                <td> Row 15- Col 1 </td>
                <td> Row 15- Col 2 </td>
                <td> Row 15- Col 3 </td>
                <td> Row 15- Col 4 </td>
            </tr>
            <tr>
                <td> Row 16- Col 1 </td>
                <td> Row 16- Col 2 </td>
                <td> Row 16- Col 3 </td>
                <td> Row 16- Col 4 </td>
            </tr>
        </tbody>
    </table>


    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery-slimScroll/1.3.8/jquery.slimscroll.min.js"></script>
    <script>
        $('.example-table tbody').slimscroll({
            height: '160px',
            alwaysVisible: true,
            color: '#333'
        })
    </script>
</body>

</html>

codegeek
fuente
1

Este es el código que me funciona para crear un thead adhesivo en una mesa con un cuerpo desplazable:

table ,tr td{
    border:1px solid red
}
tbody {
    display:block;
    height:50px;
    overflow:auto;
}
thead, tbody tr {
    display:table;
    width:100%;
    table-layout:fixed;/* even columns width , fix width of table too*/
}
thead {
    width: calc( 100% - 1em )/* scrollbar is average 1em/16px width, remove it from thead width */
}
table {
    width:400px;
}
Max Alexander Hanna
fuente
1

Para usar "overflow: scroll" debe establecer "display: block" en thead y tbody. Y eso ensucia los anchos de columna entre ellos. Pero luego puede clonar la fila thead con Javascript y pegarla en el cuerpo como una fila oculta para mantener el ancho exacto de la columna.

$('.myTable thead > tr').clone().appendTo('.myTable tbody').addClass('hidden-to-set-col-widths');

http://jsfiddle.net/Julesezaar/mup0c5hk/

<table class="myTable">
    <thead>
        <tr>
            <td>Problem</td>
            <td>Solution</td>
            <td>blah</td>
            <td>derp</td>
        </tr>
    </thead>
    <tbody></tbody>
</table>
<p>
  Some text to here
</p>

El css:

table {
  background-color: #aaa;
  width: 100%;
}

thead,
tbody {
  display: block; // Necessary to use overflow: scroll
}

tbody {
  background-color: #ddd;
  height: 150px;
  overflow-y: scroll;
}

tbody tr.hidden-to-set-col-widths,
tbody tr.hidden-to-set-col-widths td {
  visibility: hidden;
  height: 0;
  line-height: 0;
  padding-top: 0;
  padding-bottom: 0;
}

td {
  padding: 3px 10px;
}
Julesezaar
fuente
0

Prueba este jsfiddle . Esto está usando jQuery y está hecho de la respuesta de Hashem Qolami. Al principio, haz una tabla normal y luego hazla desplazable.

const makeScrollableTable = function (tableSelector, tbodyHeight) {
  let $table = $(tableSelector);
  let $bodyCells = $table.find('tbody tr:first').children();
  let $headCells = $table.find('thead tr:first').children();
  let headColWidth = 0;
  let bodyColWidth = 0;

  headColWidth = $headCells.map(function () {
    return $(this).outerWidth();
  }).get();
  bodyColWidth = $bodyCells.map(function () {
    return $(this).outerWidth();
  }).get();

  $table.find('thead tr').children().each(function (i, v) {
    $(v).css("width", headColWidth[i]+"px");
    $(v).css("min-width", headColWidth[i]+"px");
    $(v).css("max-width", headColWidth[i]+"px");
  });
  $table.find('tbody tr').children().each(function (i, v) {
    $(v).css("width", bodyColWidth[i]+"px");
    $(v).css("min-width", bodyColWidth[i]+"px");
    $(v).css("max-width", bodyColWidth[i]+"px");
  });

  $table.find('thead').css("display", "block");
  $table.find('tbody').css("display", "block");

  $table.find('tbody').css("height", tbodyHeight+"px");
  $table.find('tbody').css("overflow-y", "auto");
  $table.find('tbody').css("overflow-x", "hidden");

};
lechat
fuente