Los encabezados de tabla HTML siempre están visibles en la parte superior de la ventana cuando se visualiza una tabla grande


169

Me gustaría poder "ajustar" la presentación de una tabla HTML para agregar una característica única: al desplazarme hacia abajo por la página para que la tabla esté en la pantalla pero las filas de encabezado estén fuera de la pantalla, me gustaría que los encabezados permanezcan visible en la parte superior del área de visualización.

Esto sería conceptualmente como la función "congelar paneles" en Excel. Sin embargo, una página HTML puede contener varias tablas y solo me gustaría que suceda para la tabla que está actualmente a la vista, solo mientras está a la vista.

Nota: He visto una solución en la que el área de datos de la tabla se puede desplazar mientras los encabezados no se desplazan. Esa no es la solución que estoy buscando.


¿Está su página diseñada usando tablas? ¿no es posible convertirlo a divs primero y dejar solo los datos tabulares para las tablas?
bloquear

66
Hace poco escribí un plugin que hace esto: programacióndrunk.com
floatThead

1
Además de la solución más votada y sus derivados a continuación, el complemento de @mkoryak anterior también es bastante bueno. Asegúrese de ver eso también antes de terminar de "comprar".
DanO

Gracias dan :) También tengo algunas características
increíbles

Secundo el plugin @mkoryak floatThead; pude integrarlo rápidamente. Muchas gracias por el complemento!
w5m

Respuestas:


67

Echa un vistazo a jQuery.floatThead ( demos disponibles ) que es muy bueno, también puede funcionar con DataTables e incluso puede funcionar dentro de un overflow: autocontenedor.


Sí, funciona con desplazamiento horizontal, desplazamiento de ventana, desplazamiento interno y cambio de tamaño de ventana.
mkoryak

¿Podría agregar un violín con un código de trabajo? (Sé que hay en el sitio ...)
Michel Ayres

12
He creado una gran página de demostración / documentación. ¿Por qué necesitas un violín?
mkoryak

55
@MustModify stackoverflow no es un buen lugar para hacerme preguntas. informar un problema en github, incluso si solo se trata de cómo hacerlo funcionar. Voy a responder allí generalmente en menos de un día. Aquí probablemente responderé en menos de un año :)
mkoryak

1
@MustModify por lo que vale, ninguna de las clases en las tablas en los ejemplos son relevantes. El complemento no necesita ningún CSS o clases para funcionar, como dicen mis documentos.
mkoryak

135

Hice una solución de prueba de concepto usando jQuery .

Ver muestra aquí.

Ahora tengo este código en un repositorio de bitbucket de Mercurial . El archivo principal es tables.html.

Soy consciente de un problema con esto: si la tabla contiene anclas, y si abre la URL con el ancla especificada en un navegador, cuando se carga la página, la fila con el ancla probablemente estará oscurecida por el encabezado flotante.

Actualización 2017-12-11: veo que esto no funciona con Firefox (57) y Chrome (63) actuales. No estoy seguro de cuándo y por qué esto dejó de funcionar, o cómo solucionarlo. Pero ahora, creo que la respuesta aceptada por Hendy Irawan es superior.


Necesitaba esto para algo que estoy haciendo. Gran ayuda, gracias. Con la mía no estaba usando la ventana ya que el panel de desplazamiento era un div dentro del html. Así que tuve que cambiar floatingHeaderRow.css("top", Math.min(scrollTop - offset.top, $(this).height() - floatingHeaderRow.height()) + "px");a floatingHeaderRow.css("top", scrollTop + "px");como ocurre con el código que tenía el encabezado de la tabla estaba saltando final de la página a desaparecer con el tiempo fuera de la página.
Nalum

1
Estoy tratando de implementar esto en mi tabla. Tengo un problema con el ancho del encabezado. Los datos en las filas son valores extraídos de una base de datos, como tal, son una longitud aleatoria. Antes de desplazarse, los encabezados están en su tamaño heredado automáticamente, pero una vez que se desplaza, cambia el tamaño de los encabezados para envolver los nombres de los encabezados y, por lo tanto, tienen un ancho mucho más pequeño, por lo que los encabezados no se rastrean en la parte superior de sus respectivos columna. ¿Cómo puedo solucionar este problema?
JonYork

Hmm, no estoy seguro, según tu descripción. Sugiero 1) si es posible, muestre un ejemplo en línea; 2) hazlo como una pregunta en StackOverflow.
Craig McQueen

@ JonYork Tuve exactamente el mismo problema. Mi problema era usar <td> en el encabezado en lugar de <th>, por lo que no podía aplicar el ancho de cada columna a <th> inexistente (ver // Copy cell widths from original headerparte del código). @ Craig McQueen, edite su respuesta para que nadie más cometa este error.
aexl

@CraigMcQueen Cuando uso su increíble código (gracias) se rompe en la segunda tabla que tengo, que está detrás de otra pestaña (jQuery tab plugin). ¿Alguna idea? El encabezado se coloca en el extremo izquierdo, en lugar de seguir las columnas de ubicación. Pero funciona perfectamente en la tabla en la primera pestaña jQuery.
Richard Żak

68

Craig, refiné un poco tu código (entre otras cosas, ahora usa position: fixed) y lo envolví como un complemento jQuery.

Pruébelo aquí: http://jsfiddle.net/jmosbech/stFcx/

Y obtenga la fuente aquí: https://github.com/jmosbech/StickyTableHeaders


1
Buena idea hacer un complemento jQuery. Un par de preguntas: (1) ¿Funciona bien con desplazamiento horizontal? (2) ¿Cómo se comporta cuando se desplaza hacia abajo para que la parte inferior de la tabla se desplace desde la parte superior de la ventana? El ejemplo no permite probar esos casos.
Craig McQueen

Su ejemplo jsfiddle funciona muy bien con tablesorter, pero el código en github no. ¿Tuviste que modificar el código del clasificador de tablas?
ericslaw

Craig, el desplazamiento horizontal no debería ser un problema, ya que el encabezado se reubica horizontal y verticalmente en el desplazamiento y el cambio de tamaño. En cuanto a su segunda pregunta: el encabezado se oculta cuando la tabla sale de la ventana gráfica.
jmosbech

Eric, eso es extraño. ¿Intentaste abrir /demo/tablesorter.htm desde Github? No he modificado el código del clasificador de tablas, pero para que funcione, debe aplicar el complemento StickyTableHeader antes del clasificador de tablas.
jmosbech

2
El desplazamiento horizontal no funciona del todo, después de desplazarse una gran distancia, el thead se coloca más a la izquierda cuando se desplaza fuera de la pantalla que cuando se coloca normalmente como parte de la tabla.
Nathan Phillips

16

Si está apuntando a navegadores modernos que cumplen con css3 ( soporte de navegador: https://caniuse.com/#feat=css-sticky ) puede usar position:sticky, lo que no requiere JS y no romperá el diseño de la tabla. y td de la misma columna. Tampoco requiere un ancho de columna fijo para funcionar correctamente.

Ejemplo para una sola fila de encabezado:

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

Para los cabezas con 1 o 2 filas, puede usar algo como esto:

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

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

Es posible que deba jugar un poco con la propiedad superior del último hijo cambiando el número de píxeles para que coincida con la altura de la primera fila (+ el margen + el borde + el relleno, si corresponde), por lo que la segunda fila se pega hacia abajo abajo el primero.

Además, ambas soluciones funcionan incluso si tiene más de una tabla en la misma página: el thelemento de cada una comienza a quedar fijo cuando su posición superior es la indicada en la definición de CSS y simplemente desaparece cuando toda la tabla se desplaza hacia abajo. Entonces, si hay más mesas, todas funcionan de la misma manera.

¿Por qué usar last-child before y first-child after en el css?

Debido a que el navegador representa las reglas CSS en el mismo orden en que las escribe en el archivo CSS y, por lo tanto, si solo tiene 1 fila en el elemento thead, la primera fila es simultáneamente la última fila y la regla del primer hijo necesita para anular el último hijo. Si no, tendrá un desplazamiento de la fila de 30 px desde el margen superior, lo que supongo que no desea.

Un problema conocido de posición: pegajoso es que no funciona en los elementos o filas de la tabla: debe apuntar a los elementos. Saltar este problema se resolverá en futuras versiones del navegador.


El primer ejemplo no parece funcionar en Firefox (61). Sin embargo, si la posición pegajosa se establece en la cabeza, lo hace.
ewh

1
Podría hacer thead tr+tr thpara apuntar a la segunda fila.
Teepeemm

5

Posibles alternativas

js-floating-table-headers

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

En drupal

Tengo un sitio Drupal 6. Estaba en la página de "módulos" de administrador, ¡y noté que las tablas tenían esta característica exacta!

Mirando el código, parece ser implementado por un archivo llamado tableheader.js. Aplica la función en todas las tablas con la clase sticky-enabled.

Para un sitio de Drupal, me gustaría poder utilizar ese tableheader.jsmódulo tal cual para el contenido del usuario. tableheader.jsno parece estar presente en las páginas de contenido del usuario en Drupal. Publiqué un mensaje en el foro para preguntar cómo modificar el tema de Drupal para que esté disponible. Según una respuesta, tableheader.jsse puede agregar a un tema de Drupal usando drupal_add_js()en el tema de la template.phpsiguiente manera:

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

Su enlace de Google Code fue muy útil para mí, tahnks.
Vilius Gaidelis

5

He encontrado este problema muy recientemente. Desafortunadamente, tuve que hacer 2 tablas, una para el encabezado y otra para el cuerpo. Probablemente no sea el mejor enfoque, pero aquí va:

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

Esto funcionó para mí, probablemente no sea la forma elegante, pero funciona. Investigaré para ver si puedo hacer algo mejor, pero permite varias tablas.

Lea sobre la propiedad de desbordamiento para ver si se ajusta a sus necesidades


Hmm no funciona, voy a tratar de arreglar esto, pero el enfoque permanece, tienes que usar el desbordamiento: propiedad automática
Gab Royer

Agradezco su solución y su simplicidad, sin embargo, en mi pregunta dije "Nota: he visto una solución en la que el área de datos de la tabla se puede desplazar mientras los encabezados no se desplazan. Esa no es la solución que estoy buscando".
Craig McQueen

@GabRoyer La página w3school, a la que hizo referencia, no existe.
Farhan

Parecen haberlo movido. Corregido
Gab Royer

Otro problema con este enfoque es que si necesita adaptar algunas de las columnas a otro contenido, corre el riesgo de romper su alineación con el encabezado de columna correspondiente. En mi humilde opinión, es mejor enfrentar este problema con un enfoque que permita una gestión dinámica del contenido que mantenga una alineación perfecta de columnas y encabezados relativos. Entonces, la posición de mi humilde opinión = pegajosa es el camino a seguir.
willy wonka

3

Esto es realmente complicado tener un encabezado adhesivo en su mesa. Tenía el mismo requisito pero con asp: GridView y luego me pareció que realmente tenía un encabezado adhesivo en gridview. Hay muchas soluciones disponibles y me llevó 3 días probar todas las soluciones, pero ninguna de ellas pudo satisfacerlas.

El problema principal que enfrenté con la mayoría de estas soluciones fue el problema de alineación. Cuando intenta hacer que el encabezado flote, de alguna manera la alineación de las celdas del encabezado y las celdas del cuerpo se desvían.

Con algunas soluciones, también tuve el problema de superponer el encabezado en las primeras filas del cuerpo, lo que hace que las filas del cuerpo se oculten detrás del encabezado flotante.

Así que ahora tenía que implementar mi propia lógica para lograr esto, aunque tampoco lo considero una solución perfecta, pero esto también podría ser útil para alguien,

A continuación se muestra la tabla de muestra.

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

Nota : La tabla está envuelta en un DIV con un atributo de clase igual a 'titular de la tabla'.

A continuación se muestra el script JQuery que agregué en el encabezado de mi página html.

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

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

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

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

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

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

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

y, por último, a continuación se muestra la clase CSS para propósitos de coloración

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

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

Entonces, la idea de esta lógica es colocar la tabla en un div de soporte de tabla y crear un clon de ese titular en el lado del cliente cuando se carga la página. Ahora oculte el cuerpo de la tabla dentro del soporte de clon y coloque la parte restante del encabezado sobre el encabezado original.

La misma solución también funciona para asp: gridview, debe agregar dos pasos más para lograr esto en gridview,

  1. En el evento OnPrerender del objeto gridview en su página web, configure la sección de la tabla de la fila del encabezado igual a TableHeader.

    if (this.HeaderRow != null)
    {
        this.HeaderRow.TableSection = TableRowSection.TableHeader;
    }
  2. Y envuelve tu cuadrícula <div class="table-holder"></div>.

Nota : si su encabezado tiene controles en los que se puede hacer clic, es posible que deba agregar más script jQuery para pasar los eventos generados en el encabezado clonado al encabezado original. Este código ya está disponible en el complemento jQuery sticky-header creado por jmosbech


1 para el buen esfuerzo, pero para tablas grandes con una gran cantidad de datos, es bastante malo para clonar todo el asunto ... Me imagino que sería duplicar el tiempo de carga
khaverim

2

El uso display: fixedde la theadsección debería funcionar, pero para que solo funcione en la tabla actual a la vista, necesitará la ayuda de JavaScript. Y será complicado porque necesitará averiguar los lugares de desplazamiento y la ubicación de los elementos relativos a la ventana gráfica, que es una de las principales áreas de incompatibilidad del navegador.

Eche un vistazo a los populares marcos de JavaScript (jQuery, MooTools, YUI, etc., etc.) para ver si pueden hacer lo que quiere o hacer que sea más fácil hacer lo que quiere.


1
Gracias por el consejo. Hice una solución usando jQuery, vea mi respuesta.
Craig McQueen

Intenté esto y estoy pensando que querías decir posición en lugar de mostrar, pero ninguno funcionó para ellos en chome.
ericslaw

@ericslaw Ack: sí, quise decir position: fixed. Lo siento, no funcionó en Chrome.
staticsan

desordenó mi encabezado al ignorar los estilos de ancho
pavel_kazlou

2

Si utiliza una tabla de pantalla completa, quizás le interese configurar th para mostrar: fijo; y arriba: 0; o pruebe un enfoque muy similar a través de css.

Actualizar

Simplemente construya rápidamente una solución de trabajo con iframes (html4.0). Este ejemplo NO cumple con la norma, sin embargo, podrá solucionarlo fácilmente:

externo.html

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

test.html

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

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

@ a_m0d, cierto ... pero la solicitud suena muy confusa. O lo estamos malentendiendo, o el autor de la pregunta no comprende completamente lo que quiere.
Sampson

Aquí hay otra solución usando algunos imaputz.com/cssStuff/bigFourVersion.html de
merkuro

2

La respuesta más simple solo usando CSS: D !!!

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

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

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


1
Gracias David, es el mejor enfoque que he encontrado en esta pregunta
Tomasz Smykowski

0

¡Esa prueba de concepto que hiciste fue genial! Sin embargo, también encontré este complemento jQuery que parece estar funcionando muy bien. ¡Espero eso ayude!


Parece que implementa una característica diferente . Como dije en mi pregunta original: "Nota: He visto una solución en la que el área de datos de la tabla se puede desplazar mientras los encabezados no se desplazan. Esa no es la solución que estoy buscando".
Craig McQueen

2
probar el complemento que mencionaste acaba de desordenar el encabezado de mi tabla. No pude usarlo.
pavel_kazlou

0

Es frustrante que lo que funciona muy bien en un navegador no funciona en otros. Lo siguiente funciona en Firefox, pero no en Chrome o IE:

<table width="80%">

 <thead>

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

 </thead>

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

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

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

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

 </tbody>

</table>

44
Lo estoy probando en Firefox 8.0, y no parece hacer nada. ¿Qué hace?
Craig McQueen

¿Qué es px? ¿Es esa unidad heredada utilizada por personas en el 90 cuando un dispositivo de visualización tenía 72 ppp?
ceving

Estoy de acuerdo: es muy frustrante, desafortunadamente los desarrolladores de navegadores no respetan los estándares en cada situación ... ¡y hace algunos años era aún peor! Ahora se han resuelto algunos problemas y más navegadores se comportan de una manera más estandarizada, pero aún quedan muchos pasos por hacer: esperemos y recemos :-)
willy wonka
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.