Encabezado de tabla para permanecer fijo en la parte superior cuando el usuario lo desplaza fuera de la vista con jQuery


Estoy tratando de diseñar una tabla HTML donde el encabezado permanezca en la parte superior de la página cuando Y SOLO cuando el usuario lo desplaza fuera de la vista. Por ejemplo, la tabla puede estar 500 píxeles por debajo de la página, ¿cómo hago para que si el usuario desplaza el encabezado fuera de la vista (el navegador detecta que ya no está en la vista de Windows de alguna manera), se quede en la parte superior? ¿Alguien puede darme una solución Javascript para esto?

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

Así que en el ejemplo anterior, quiero que el <thead> se desplace con el avísame si no está a la vista.

IMPORTANTE: Estoy NO buscando una solución donde el <tbody> tendrá una barra de desplazamiento (overflow:auto).

Author: Sam Dufel, 2011-01-17

21 answers

Haría algo como esto pulsando en el controlador de eventos scroll en window, y usando otro table con una posición fija para mostrar el encabezado en la parte superior de la 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();
    }
});

Esto mostrará la cabeza de la mesa cuando el usuario se desplace lo suficientemente lejos como para ocultar la cabeza de la mesa original. Se ocultará de nuevo cuando el usuario haya desplazado la página lo suficientemente lejos de nuevo.

Trabajando ejemplo: http://jsfiddle.net/andrewwhitaker/fj8wM/

 122
Author: Andrew Whitaker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-08 17:53:56

Bueno, estaba tratando de obtener el mismo efecto sin recurrir a columnas de tamaño fijo o tener una altura fija para toda la tabla.

La solución que se me ocurrió es un hack. Consiste en duplicar toda la tabla y luego ocultar todo menos el encabezado, y hacer que tenga una posición fija.

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>

CSS

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<anchor_bottom) {
    clone_table = $("#clone");
    if(clone_table.length == 0){
        clone_table = $("#maintable").clone();
        clone_table.attr('id', 'clone');
        clone_table.css({position:'fixed',
                 'pointer-events': 'none',
                 top:0});
        clone_table.width($("#maintable").width());
        $("#table-container").append(clone_table);
        $("#clone").css({visibility:'hidden'});
        $("#clone thead").css({'visibility':'visible','pointer-events':'auto'});
    }
    } else {
    $("#clone").remove();
    }
}
$(window).scroll(moveScroll); 

Ver aquí: http://jsfiddle.net/QHQGF/7/

Editar: actualizado el código para que el thead puede recibir eventos de puntero (por lo que los botones y enlaces en el encabezado aún funcionan). Esto soluciona el problema reportado por luhfluh y Joe M.

Nuevo jsfiddle aquí: http://jsfiddle.net/cjKEx /

 43
Author: entropy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-24 20:45:47

Pude solucionar el problema con el cambio de ancho de columna. Empecé con la solución de Andrew arriba (muchas gracias!) y luego agregó un pequeño bucle para establecer los anchos de los td clonados:

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

Esto resuelve el problema sin tener que clonar toda la tabla y ocultar el cuerpo. Soy nuevo en JavaScript y jQuery (y en stack overflow), por lo que cualquier comentario es apreciado.

 25
Author: rockusbacchus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-18 00:27:48

Escribí un plugin que hace esto. He estado trabajando en él durante aproximadamente un año y creo que maneja todos los casos de esquina bastante bien:

  • desplazamiento dentro de un contenedor con desbordamiento
  • desplazamiento dentro de una ventana
  • teniendo cuidado de lo que sucede cuando se cambia el tamaño de la ventana
  • mantener tus eventos vinculados al encabezado
  • lo más importante es que no te obliga a cambiar el css de tu tabla para que funcione

Aquí hay algunos demos / docs:
http://mkoryak.github.io/floatThead /

 21
Author: mkoryak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-05 20:56:27

Esta es, con mucho, la mejor solución que he encontrado para tener un encabezado de tabla fijo.

ACTUALIZACIÓN 5/11: Corregido el error de desplazamiento horizontal señalado por Kerry Johnson

Codepen: https://codepen.io/josephting/pen/demELL

;(function($) {
   $.fn.fixMe = function() {
      return this.each(function() {
         var $this = $(this),
            $t_fixed;
         function init() {
            $this.wrap('<div class="container" />');
            $t_fixed = $this.clone();
            $t_fixed.find("tbody").remove().end().addClass("fixed").insertBefore($this);
            resizeFixed();
         }
         function resizeFixed() {
           $t_fixed.width($this.outerWidth());
            $t_fixed.find("th").each(function(index) {
               $(this).css("width",$this.find("th").eq(index).outerWidth()+"px");
            });
         }
         function scrollFixed() {
            var offsetY = $(this).scrollTop(),
            offsetX = $(this).scrollLeft(),
            tableOffsetTop = $this.offset().top,
            tableOffsetBottom = tableOffsetTop + $this.height() - $this.find("thead").height(),
            tableOffsetLeft = $this.offset().left;
            if(offsetY < tableOffsetTop || offsetY > tableOffsetBottom)
               $t_fixed.hide();
            else if(offsetY >= tableOffsetTop && offsetY <= tableOffsetBottom && $t_fixed.is(":hidden"))
               $t_fixed.show();
            $t_fixed.css("left", tableOffsetLeft - offsetX + "px");
         }
         $(window).resize(resizeFixed);
         $(window).scroll(scrollFixed);
         init();
      });
   };
})(jQuery);

$(document).ready(function(){
   $("table").fixMe();
   $(".up").click(function() {
      $('html, body').animate({
      scrollTop: 0
   }, 2000);
 });
});
body{
  font:1.2em normal Arial,sans-serif;
  color:#34495E;
}

h1{
  text-align:center;
  text-transform:uppercase;
  letter-spacing:-2px;
  font-size:2.5em;
  margin:20px 0;
}

.container{
  width:90%;
  margin:auto;
}

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

.blue{
  border:2px solid #1ABC9C;
}

.blue thead{
  background:#1ABC9C;
}

.purple{
  border:2px solid #9B59B6;
}

.purple thead{
  background:#9B59B6;
}

thead{
  color:white;
}

th,td{
  text-align:center;
  padding:5px 0;
}

tbody tr:nth-child(even){
  background:#ECF0F1;
}

tbody tr:hover{
background:#BDC3C7;
  color:#FFFFFF;
}

.fixed{
  top:0;
  position:fixed;
  width:auto;
  display:none;
  border:none;
}

.scrollMore{
  margin-top:600px;
}

.up{
  cursor:pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>&darr; SCROLL &darr;</h1>
<table class="blue">
  <thead>
    <tr>
      <th>Colonne 1</th>
      <th>Colonne 2</th>
      <th>Colonne 3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Non</td>
      <td>MaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
       <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
  </tbody>
</table>

<h1 class="scrollMore">&darr; SCROLL MORE &darr;</h1>
<table class="purple">
  <thead>
    <tr>
      <th>Colonne 1</th>
      <th>Colonne 2</th>
      <th>Colonne 3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
       <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
    <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
       <tr>
      <td>Non</td>
      <td>Mais</td>
      <td>Allo !</td>
    </tr>
  </tbody>
</table>
<h1 class="up scrollMore">&uarr; UP &uarr;</h1>
 15
Author: josephting,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-11 04:17:39

CSS puro (sin soporte de IE y Edge en mayo de 2017):

table thead {
    position: -webkit-sticky;
    position: sticky;
    top: 0;
    z-index: 5;
    background: #fff;
}
 11
Author: Ihor Zenich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-04 14:56:24

La mejor solución es usar este plugin de jquery:

Https://github.com/jmosbech/StickyTableHeaders

Este plugin funcionó muy bien para nosotros y probamos muchas otras soluciones. Lo probamos en IE, Chrome y Firefox

 7
Author: Janning,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-11 08:46:14

Encontré una biblioteca jQuery simple llamada Sticky Table Headers. Dos líneas de código e hizo exactamente lo que quería. Las soluciones anteriores no administran los anchos de columna, por lo que si tiene celdas de tabla que ocupan mucho espacio, el tamaño resultante del encabezado persistente no coincidirá con el ancho de la tabla.

Http://plugins.jquery.com/StickyTableHeaders /

Información de uso aquí: https://github.com/jmosbech/StickyTableHeaders

 4
Author: Lok Yan Wong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-07 16:22:46

Bueno, después de revisar todas las soluciones disponibles escribí plugin que puede congelar cualquier fila (no solo th) en la parte superior de la página o contenedor. Es muy simple y muy rápido. Siéntase libre de usarlo. http://maslianok.github.io/stickyRows /

 3
Author: Vitalii Maslianok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-17 08:36:00

Yo también experimenté los mismos problemas con el formato del borde que no se muestra usando el código de entrophy, pero algunos pequeños arreglos y ahora la tabla es expandible y muestra todas las reglas de estilo CSS que puede agregar.

A css añadir:

#maintable{width: 100%}    

Entonces aquí está el nuevo 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 < anchor_bottom) {
        clone_table = $("#clone");
        if(clone_table.length === 0) {          
            clone_table = $("#maintable").clone();
            clone_table.attr({id: "clone"})
            .css({
                position: "fixed",
                "pointer-events": "none",
                 top:0
            })
            .width($("#maintable").width());

            $("#table-container").append(clone_table);
            // dont hide the whole table or you lose border style & 
            // actively match the inline width to the #maintable width if the 
            // container holding the table (window, iframe, div) changes width          
            $("#clone").width($("#maintable").width());
            // only the clone thead remains visible
            $("#clone thead").css({
                visibility:"visible"
            });
            // clone tbody is hidden
            $("#clone tbody").css({
                visibility:"hidden"
            });
            // add support for a tfoot element
            // and hide its cloned version too
            var footEl = $("#clone tfoot");
            if(footEl.length){
                footEl.css({
                    visibility:"hidden"
                });
            }
        }
    } 
    else {
        $("#clone").remove();
    }
}
$(window).scroll(moveScroll);
 2
Author: seeit360,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-13 03:23:53

Aquí hay una solución que se basa en la respuesta aceptada. Corrige: anchos de columna, estilo de tabla coincidente y cuando la tabla se desplaza en un div de contenedor.

Uso

Asegúrese de que su tabla tenga una etiqueta <thead> porque solo se corregirá el contenido ad.

$("#header-fixed").fixHeader();

JavaScript

//Custom JQuery Plugin
(function ($) {
    $.fn.fixHeader = function () {
        return this.each(function () {
            var $table = $(this);
            var $sp = $table.scrollParent();
            var tableOffset = $table.position().top;
            var $tableFixed = $("<table />")
                .prop('class', $table.prop('class'))
                .css({ position: "fixed", "table-layout": "fixed", display: "none", "margin-top": "0px" });
            $table.before($tableFixed);
            $tableFixed.append($table.find("thead").clone());

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

                if (offset > tableOffset && $tableFixed.is(":hidden")) {
                    $tableFixed.show();
                    var p = $table.position();
                    var offset = $sp.offset();

                    //Set the left and width to match the source table and the top to match the scroll parent
                    $tableFixed.css({ left: p.left + "px", top: (offset ? offset.top : 0) + "px", }).width($table.width());

                    //Set the width of each column to match the source table
                    $.each($table.find('th, td'), function (i, th) {
                        $($tableFixed.find('th, td')[i]).width($(th).width());
                    });

                }
                else if (offset <= tableOffset && !$tableFixed.is(":hidden")) {
                    $tableFixed.hide();
                }
            });
        });
    };
})(jQuery);
 2
Author: Ben Gripka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-08 18:42:12

Esto le ayudará a tener un encabezado fijo que también se puede desplazar horizontalmente con los datos.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Shubh</title>



<script type="text/javascript">
    var lastSeen = [ 0, 0 ];
    function checkScroll(div1, div2) {
        if (!div1 || !div2)
            return;
        var control = null;
        if (div1.scrollLeft != lastSeen[0])
            control = div1;
        else if (div2.scrollLeft != lastSeen[1])
            control = div2;
        if (control == null)
            return;
        else
            div1.scrollLeft = div2.scrollLeft = control.scrollLeft;
        lastSeen[0] = div1.scrollLeft;
        lastSeen[1] = div2.scrollLeft;
    }

    window
            .setInterval(
                    "checkScroll(document.getElementById('innertablediv'), document.getElementById('headertable'))",
                    1);
</script>

<style type="text/css">
#full {
    width: 400px;
    height: 300px;
}

#innertablediv {
    height: 200px;
    overflow: auto;
}

#headertable {
    overflow: hidden;
}
</style>
</head>
<body>

    <div id="full">




        <div id="headertable">
            <table border="1" bgcolor="grey" width="150px" id="headertable">
                <tr>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>

                    <td>&nbsp;&nbsp;&nbsp;</td>
                </tr>

            </table>
        </div>




        <div id="innertablediv">

            <table border="1" id="innertableid">
                <tr>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                </tr>
                <tr>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                </tr>
                <tr>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                </tr>
                <tr>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                </tr>
                <tr>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                </tr>
                <tr>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                </tr>
                <tr>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                </tr>
                <tr>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                </tr>
                <tr>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                    <td>shubh, ansh</td>
                </tr>

            </table>
        </div>
    </div>
</body>
</html>
 1
Author: user2669926,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-10 07:05:28
function fix_table_header_position(){
 var width_list = [];
 $("th").each(function(){
    width_list.push($(this).width());
 });
 $("tr:first").css("position", "absolute");
 $("tr:first").css("z-index", "1000");
 $("th, td").each(function(index){
    $(this).width(width_list[index]);
 });

 $("tr:first").after("<tr height=" + $("tr:first").height() + "></tr>");}

Esta es mi solución

 1
Author: Jiu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-30 08:50:51

Un poco tarde para el grupo, pero aquí hay una implementación que funciona con varias tablas en la misma página y "jank" gratis (usando requestAnimationFrame). Además, no es necesario proporcionar ningún ancho en las columnas. El desplazamiento horizontal también funciona.

Los encabezados están definidos en un div por lo que es libre de agregar cualquier marcado allí (botones me gusta), si es necesario. Este es todo el HTML que se necesita:

<div class="tbl-resp">
  <table id="tbl1" class="tbl-resp__tbl">
     <thead>
      <tr>
        <th>col 1</th>
        <th>col 2</th>
        <th>col 3</th>
      </tr>
    </thead> 
  </table>
</div>

Https://jsfiddle.net/lloydleo/bk5pt5gs /

 1
Author: Leo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-26 22:22:22

En esta solución el encabezado fijo se crea dinámicamente, el contenido y el estilo se clona de THEAD

Todo lo que necesitas son dos líneas por ejemplo:

var $myfixedHeader = $("#Ttodo").FixedHeader(); //create fixed header $(window).scroll($myfixedHeader.moveScroll); //bind function to scroll event

Mi plugin jquery FixedHeader y getStyleObject proporcionado a continuación puede poner en el archivo .js

// JAVASCRIPT



/*
 * getStyleObject Plugin for jQuery JavaScript Library
 * From: http://upshots.org/?p=112
 
Basic usage:
$.fn.copyCSS = function(source){
  var styles = $(source).getStyleObject();
  this.css(styles);
}
*/

(function($){
    $.fn.getStyleObject = function(){
        var dom = this.get(0);
        var style;
        var returns = {};
        if(window.getComputedStyle){
            var camelize = function(a,b){
                return b.toUpperCase();
            };
            style = window.getComputedStyle(dom, null);
            for(var i = 0, l = style.length; i < l; i++){
                var prop = style[i];
                var camel = prop.replace(/\-([a-z])/g, camelize);
                var val = style.getPropertyValue(prop);
                returns[camel] = val;
            };
            return returns;
        };
        if(style = dom.currentStyle){
            for(var prop in style){
                returns[prop] = style[prop];
            };
            return returns;
        };
        return this.css();
    }
})(jQuery);



   
//Floating Header of long table  PiotrC
(function ( $ ) {
    var tableTop,tableBottom,ClnH;
    $.fn.FixedHeader = function(){
        tableTop=this.offset().top,
        tableBottom=this.outerHeight()+tableTop;
        //Add Fixed header
        this.after('<table id="fixH"></table>');
        //Clone Header
        ClnH=$("#fixH").html(this.find("thead").clone());
        //set style
        ClnH.css({'position':'fixed', 'top':'0', 'zIndex':'60', 'display':'none',
        'border-collapse': this.css('border-collapse'),
		'border-spacing': this.css('border-spacing'),
        'margin-left': this.css('margin-left'),
        'width': this.css('width')            
        });
        //rewrite style cell of header
        $.each(this.find("thead>tr>th"), function(ind,val){
            $(ClnH.find('tr>th')[ind]).css($(val).getStyleObject());
        });
    return ClnH;}
    
    $.fn.moveScroll=function(){
        var offset = $(window).scrollTop();
        if (offset > tableTop && offset<tableBottom){
            if(ClnH.is(":hidden"))ClnH.show();
            $("#fixH").css('margin-left',"-"+$(window).scrollLeft()+"px");
        }
        else if (offset < tableTop || offset>tableBottom){
            if(!ClnH.is(':hidden'))ClnH.hide();
        }
    };
})( jQuery );





var $myfixedHeader = $("#repTb").FixedHeader();
$(window).scroll($myfixedHeader.moveScroll);
/* CSS - important only NOT transparent background */

#repTB{border-collapse: separate;border-spacing: 0;}

#repTb thead,#fixH thead{background: #e0e0e0 linear-gradient(#d8d8d8 0%, #e0e0e0 25%, #e0e0e0 75%, #d8d8d8 100%) repeat scroll 0 0;border:1px solid #CCCCCC;}

#repTb td{border:1px solid black}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>


<h3>example</h3> 
<table id="repTb">
<thead>
<tr><th>Col1</th><th>Column2</th><th>Description</th></tr>
</thead>
<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>
<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>
<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>
</table>
 1
Author: Piotr C.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-30 19:40:32

Cree una tabla adicional con el mismo encabezado que la tabla principal. Simplemente ponga thead en la nueva tabla con una fila y todos los encabezados en ella. Hacer posición absoluta y fondo blanco. Para la tabla principal póngalo en un div y use algo de altura y desbordamiento-y scroll. De esta manera nuestra nueva mesa superará la cabecera de la mesa principal y se quedará allí. Rodear todo en un div. A continuación se muestra el código aproximado para hacerlo.

      <div class="col-sm-8">

        <table id="header-fixed" class="table table-bordered table-hover" style="width: 351px;position: absolute;background: white;">
        <thead>
        <tr>
            <th>Col1</th>
            <th>Col2</th>
            <th>Col3</th>
        </tr>
    </thead>
      </table>


    <div style="height: 300px;overflow-y: scroll;">
          <table id="tableMain" class="table table-bordered table-hover" style="table-layout:fixed;overflow-wrap: break-word;cursor:pointer">
<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>
              </div>
        </div>
 1
Author: Novice_JS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-12 17:45:32

Puede utilizar este enfoque, HTML puro y CSS no necesita JS:)

.table-fixed-header {
  display: flex;
  justify-content: space-between;
  margin-right: 18px
}

.table-fixed {
  display: flex;
  justify-content: space-between;
  height: 150px;
  overflow: scroll;
}

.column {
  flex-basis: 24%;
  border-radius: 5px;
  padding: 5px;
  text-align: center;
}
.column .title {
  border-bottom: 2px grey solid;
  border-top: 2px grey solid;
  text-align: center;
  display: block;
  font-weight: bold;
}

.cell {
  padding: 5px;
  border-right: 1px solid;
  border-left: 1px solid;
}

.cell:nth-of-type(even) {
  background-color: lightgrey;
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Fixed header Bin</title>
</head>
<body>
<div class="table-fixed-header">
    
    <div class="column">
      <span class="title">col 1</span>
    </div>
    <div class="column">
      <span class="title">col 2</span>
    </div>
    <div class="column">
      <span class="title">col 3</span>
    </div>
    <div class="column">
      <span class="title">col 4</span>
    </div>
    
  </div>
  
  <div class="table-fixed">
    
    <div class="column">
      <div class="cell">alpha</div>
      <div class="cell">beta</div>
      <div class="cell">ceta</div>
    </div>
    
    <div class="column">
      <div class="cell">alpha</div>
      <div class="cell">beta</div>
      <div class="cell">ceta</div>
      <div class="cell">alpha</div>
      <div class="cell">beta</div>
      <div class="cell">ceta</div>
      <div class="cell">alpha</div>
      <div class="cell">beta</div>
      <div class="cell">ceta</div>
    </div>
    
    <div class="column">
      <div class="cell">alpha</div>
      <div class="cell">beta</div>
      <div class="cell">ceta</div>
      <div class="cell">beta</div>
      <div class="cell">beta</div>
      <div class="cell">beta</div>
      
    </div>
    
    <div class="column">
      <div class="cell">alpha</div>
      <div class="cell">beta</div>
      <div class="cell">ceta</div>
    </div>
    
  </div>
</body>
</html>
 1
Author: xelilof,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-09 14:40:35

div.wrapper {
    padding:20px;
}
table.scroll thead {
    width: 100%;
    background: #FC6822;
}
table.scroll thead tr:after {
    content: '';
    overflow-y: scroll;
    visibility: hidden;
}
table.scroll thead th {
    flex: 1 auto;
    display: block;
    color: #fff;
}
table.scroll tbody {
    display: block;
    width: 100%;
    overflow-y: auto;
    height: auto;
    max-height: 200px;
}
table.scroll thead tr,
table.scroll tbody tr {
    display: flex;
}
table.scroll tbody tr td {
    flex: 1 auto;
    word-wrap: break;
}
table.scroll thead tr th,
table.scroll tbody tr td {
    width: 25%;
    padding: 5px;
    text-align-left;
    border-bottom: 1px solid rgba(0,0,0,0.3);
}
<div class="wrapper">
    <table border="0" cellpadding="0" cellspacing="0" class="scroll">
        <thead>
            <tr>
                <th>Name</th>
                <th>Vorname</th>
                <th>Beruf</th>
                <th>Alter</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>Müller</td>
                <td>Marie</td>
                <td>Künstlerin</td>
                <td>26</td>
            </tr>
            <tr>
                <td>Meier</td>
                <td>Stefan</td>
                <td>Chemiker</td>
                <td>52</td>
            </tr>
            <tr>
                <td>Schmidt</td>
                <td>Sabrine</td>
                <td>Studentin</td>
                <td>38</td>
            </tr>
            <tr>
                <td>Mustermann</td>
                <td>Max</td>
                <td>Lehrer</td>
                <td>41</td>
            </tr>
            <tr>
                <td>Müller</td>
                <td>Marie</td>
                <td>Künstlerin</td>
                <td>26</td>
            </tr>
            <tr>
                <td>Meier</td>
                <td>Stefan</td>
                <td>Chemiker</td>
                <td>52</td>
            </tr>
            <tr>
                <td>Schmidt</td>
                <td>Sabrine</td>
                <td>Studentin</td>
                <td>38</td>
            </tr>
            <tr>
                <td>Mustermann</td>
                <td>Max</td>
                <td>Lehrer</td>
                <td>41</td>
            </tr>
            <tr>
                <td>Müller</td>
                <td>Marie</td>
                <td>Künstlerin</td>
                <td>26</td>
            </tr>
            <tr>
                <td>Meier</td>
                <td>Stefan</td>
                <td>Chemiker</td>
                <td>52</td>
            </tr>
            <tr>
                <td>Schmidt</td>
                <td>Sabrine</td>
                <td>Studentin</td>
                <td>38</td>
            </tr>
            <tr>
                <td>Mustermann</td>
                <td>Max</td>
                <td>Lehrer</td>
                <td>41</td>
            </tr>
        </tbody>
    </table>
</div>

Demo: css fixed table header demo

 1
Author: revilodesign.de,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-12 08:41:50

Esto se puede lograr usando la propiedad de estilo transform. Todo lo que tiene que hacer es envolver su mesa en algún div con altura fija y desbordamiento establecido en auto, por ejemplo:

.tableWrapper {
  overflow: auto;
  height: calc( 100% - 10rem );
}

Y luego puede adjuntar el controlador oncroll, aquí tiene el método que encuentra cada tabla envuelta con <div class="tableWrapper"></div>:

  fixTables () {
    document.querySelectorAll('.tableWrapper').forEach((tableWrapper) => {
      tableWrapper.addEventListener('scroll', () => {
        var translate = 'translate(0,' + tableWrapper.scrollTop + 'px)'
        tableWrapper.querySelector('thead').style.transform = translate
      })
    })
  }

Y aquí está el ejemplo de trabajo de esto en acción (he usado bootstrap para hacerlo más bonito): fiddle

Para aquellos que también quieren apoyar IE y Edge, aquí es el fragmento:

  fixTables () {
    const tableWrappers = document.querySelectorAll('.tableWrapper')
    for (let i = 0, len = tableWrappers.length; i < len; i++) {
      tableWrappers[i].addEventListener('scroll', () => {
        const translate = 'translate(0,' + tableWrappers[i].scrollTop + 'px)'
        const headers = tableWrappers[i].querySelectorAll('thead th')
        for (let i = 0, len = headers.length; i < len; i++) {
          headers[i].style.transform = translate
        }
      })
    }
  }

En IE y Edge scroll es un poco rezagado... pero funciona

Aquí está la respuesta que me ayuda a averiguar esto: respuesta

 0
Author: Daniel Budzyński,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-26 11:35:14

He probado la mayoría de estas soluciones, y finalmente encontré (IMO) la mejor solución moderna:

CSS grids


Con las cuadrículas CSS, puede definir una 'cuadrícula', y puede finalmente crear una solución agradable, libre de javascript, para una tabla con un encabezado fijo y contenido desplazable. La altura del encabezado puede incluso dinámico.

CSS : Mostrar como cuadrícula, y establecer el número de template-rows:

.grid {
    display: grid;
    grid-template-rows: 50px auto; // For fixed height header
    grid-template-rows: auto auto; // For dynamic height header
}

HTML: Crear un contenedor de cuadrícula y el número de rows definido:

<div class="grid">
    <div></div>
    <div></div>
</div>

Aquí está el ejemplo de trabajo:

CSS

body {
  margin: 0px;
  padding: 0px;
  text-align: center;
}

.table {
  width: 100%;
  height: 100%;
  display: grid;
  grid-template-rows: 50px auto;
}
.table-heading {
  background-color: #ddd;
}
.table-content {
  overflow-x: hidden;
  overflow-y: scroll;
}

HTML

<html>
    <head>
    </head>
    <body>
        <div class="table">
            <div class="table-heading">
                HEADING
            </div>
            <div class="table-content">
                CONTENT - CONTENT - CONTENT <br/>
                CONTENT - CONTENT - CONTENT <br/>
                CONTENT - CONTENT - CONTENT <br/>
                CONTENT - CONTENT - CONTENT <br/>
                CONTENT - CONTENT - CONTENT <br/>
                CONTENT - CONTENT - CONTENT <br/>
            </div>
        </div>
    </body>
</html>
 0
Author: Jeffrey Roosendaal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-15 10:08:56

Lo he probado usando transformación:traducir. Si bien funciona bien en Firefox y Chrome, simplemente no hay ninguna función en IE11. No hay barras de desplazamiento dobles. Admite tabla tfoot y leyenda. Javascript puro, sin jQuery.

Http://jsfiddle.net/wbLqzrfb/42 /

thead.style.transform="translate(0,"+(dY-top-1)+"px)";
 0
Author: Henrik Haftmann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-16 16:21:20