Cómo lidiar con los saltos de página al imprimir una tabla HTML grande

261

Tengo un proyecto que requiere imprimir una tabla HTML con muchas filas.

Mi problema es la forma en que se imprime la tabla en varias páginas. A veces cortará una fila por la mitad, haciéndola ilegible porque la mitad está en el borde de una página y el resto se imprime en la parte superior de la página siguiente.

La única solución plausible que se me ocurre es usar DIV apilados en lugar de una tabla y forzar saltos de página si es necesario ... pero antes de pasar por todo el cambio, pensé que podría preguntar aquí antes.

h3.
fuente
28
En una tangente, podría valer la pena agregar un <thead>a su tabla con el siguiente CSS thead {display: table-header-group; }para imprimir el encabezado de la tabla en todas las páginas posteriores (útil para taaaaaaaaaaaa tablas de datos).
David dice que reinstale a Mónica el

Respuestas:

277
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test</title>
<style type="text/css">
    table { page-break-inside:auto }
    tr    { page-break-inside:avoid; page-break-after:auto }
    thead { display:table-header-group }
    tfoot { display:table-footer-group }
</style>
</head>
<body>
    <table>
        <thead>
            <tr><th>heading</th></tr>
        </thead>
        <tfoot>
            <tr><td>notes</td></tr>
        </tfoot>
        <tbody>
        <tr>
            <td>x</td>
        </tr>
        <tr>
            <td>x</td>
        </tr>
        <!-- 500 more rows -->
        <tr>
            <td>x</td>
        </tr>
    </tbody>
    </table>
</body>
</html>
Sinan Ünür
fuente
18
Esto también falla en los navegadores WebKit (por ejemplo, Safari y Chrome)
Michael Haren
55
Si bien esta es la forma de hacer esto que cumple con los estándares, el único navegador que actualmente implementa el estándar es Opera. Tenga en cuenta que esto es parte de css2, por lo que es probable que la falta de implementación sea un problema en el futuro, porque aparentemente a nadie le importa.
pkh
16
La especificación CSS 2.1 indica que los atributos de estilo de salto de página solo se aplican a elementos de nivel de bloque. El modo de visualización predeterminado para las filas de la tabla es table-row. Desafortunadamente, los elementos de la tabla no son elementos de nivel de bloque por defecto, incluida la tabla misma.
lsuarez
2
@ SinanÜnür No es un requisito, por lo que no puede confiar en él, y desafortunadamente de mis pruebas puedo ver que webkit vio "puede" e ignoró cualquier cosa más allá. Curiosamente, IE tiene un soporte de impresión de tabla grande bastante agradable. Nunca pensé que cantaría sus alabanzas en un punto dado.
lsuarez
66
Puedo confirmar que esto NO funciona bien en Chrome o en cualquier otro navegador Webkit (por ejemplo, Safari, Opera), a menos que, por "funciona bien", se refiera a "excluye cualquier función que se considere opcional". Creo que lo que la mayoría de la gente quiere es ejecutar encabezados y pies de página, y tablas que solo permitan saltos de página entre filas, ninguna de las cuales está implementada en Webkit a partir del 13/11/2015.
DoctorDestructo
47

Nota: cuando use el salto de página después: siempre para la etiqueta, creará un salto de página después del último bit de la tabla, ¡creando una página completamente en blanco al final cada vez! Para solucionar esto, simplemente cámbielo a salto de página después: automático. Se romperá correctamente y no creará una página en blanco adicional.

<html>
<head>
<style>
@media print
{
  table { page-break-after:auto }
  tr    { page-break-inside:avoid; page-break-after:auto }
  td    { page-break-inside:avoid; page-break-after:auto }
  thead { display:table-header-group }
  tfoot { display:table-footer-group }
}
</style>
</head>

<body>
....
</body>
</html>
Josh P
fuente
Funciona para mí en Chrome y es una buena solución CSS simple.
Ryan
1
Estoy intentando la misma solución, pero no rompe los datos de la tabla y desaparece los datos adicionales en lugar de mostrarlos en la página siguiente. ¿Alguna suposición?
Puntero nulo
24

Expandiendo desde la solución Sinan Ünür:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test</title>
<style type="text/css">
    table { page-break-inside:auto }
    div   { page-break-inside:avoid; } /* This is the key */
    thead { display:table-header-group }
    tfoot { display:table-footer-group }
</style>
</head>
<body>
    <table>
        <thead>
            <tr><th>heading</th></tr>
        </thead>
        <tfoot>
            <tr><td>notes</td></tr>
        </tfoot>
        <tr>
            <td><div>Long<br />cell<br />should'nt<br />be<br />cut</div></td>
        </tr>
        <tr>
            <td><div>Long<br />cell<br />should'nt<br />be<br />cut</div></td>
        </tr>
        <!-- 500 more rows -->
        <tr>
            <td>x</td>
        </tr>
    </tbody>
    </table>
</body>
</html>

Parece que page-break-inside:avoiden algunos navegadores solo se tiene en cuenta para los elementos de bloque, no para la celda, la tabla, la fila ni el bloque en línea.

Si intenta usar display:blockla TRetiqueta y la usa allí page-break-inside:avoid, funciona, pero se complica con el diseño de su tabla.

vicenteherrera
fuente
2
Aquí hay una manera fácil de agregar los divs dinámicamente con jquery:$(document).ready(function(){$("table tbody th, table tbody td").wrapInner("<div></div>");});
Chris Bloom
1
Gracias a sinan ürün, vicenteherrera y Chrisbloom7. ¡Apliqué la combinación de tus respuestas y ahora funciona!
Nurhak Kaya
Puede intentar configurar @media CSS en tr { display: block; }Solo impresión, en lugar de agregar todos los <div>elementos extraños . (No lo he probado pero vale la pena mirarlo)
Stephen R
11

Ninguna de las respuestas aquí funcionó para mí en Chrome. AAverin en GitHub ha creado algunos Javascript útiles para este propósito y esto funcionó para mí:

Simplemente agregue el js a su código y agregue la clase 'splitForPrint' a su tabla y dividirá la tabla en varias páginas y agregará el encabezado de la tabla a cada página.

MDave
fuente
¿Tiene una muestra sobre cómo aplicar esto? He estado tratando de asignar mi tabla className como, splitForPrintpero en el JS no hay ningún lugar donde haya tomado la referencia del elemento usando className splitForPrint. Solo la parte donde var splitClassName = 'splitForPrint';pero eso es todo.
Compaq LE2202x
Down votó porque el script con el que se vinculó no resuelve el problema del OP sin una selección y reconfiguración considerable, y no proporcionó ningún ejemplo de cómo se podría hacer.
Chris Bloom
Funcionó como un encanto para mí, ninguna de las otras soluciones funcionó. +1 Tuve que agregar un poco de CSS para obtener los saltos correctos .page-break {page-break-after: siempre; }
fhugas 01 de
Sí, agregando .page-break {page-break-after: siempre; } me salvó el día!
Milodky
7

Use estas propiedades CSS:

page-break-after

page-break-before 

Por ejemplo:

<html>
<head>
<style>
@media print
{
table {page-break-after:always}
}
</style>
</head>

<body>
....
</body>
</html>

vía

marcgg
fuente
No estoy seguro, tendrás que comprobarlo. Si no es así, dividido en diferentes matrices y separar las matrices por un div vacío
marcgg
Tendrás que aplicarlo a la fila de la tabla o incluso a la celda, pero no a la tabla, creo. Aparte de eso, debería funcionar.
Pekka el
2
No funciona en cromo. Se ignora como si 13/06/2012 cuando se aplica a TR
ladieu
5

Recientemente resolví este problema con una buena solución.

CSS :

.avoidBreak { 
    border: 2px solid;
    page-break-inside:avoid;
}

JS :

function Print(){
    $(".tableToPrint td, .tableToPrint th").each(function(){ $(this).css("width",  $(this).width() + "px")  });
    $(".tableToPrint tr").wrap("<div class='avoidBreak'></div>");
    window.print();
}

¡Funciona de maravilla!

Wendel Tavares
fuente
2

Terminé siguiendo el enfoque de @ vicenteherrera, con algunos ajustes (que posiblemente sean específicos de bootstrap 3).

Básicamente; no podemos romper trs, o tds porque no son elementos de nivel de bloque. Así que incorporamos divs en cada uno y aplicamos nuestras page-break-*reglas contra el div. En segundo lugar; agregamos un poco de relleno en la parte superior de cada uno de estos divs, para compensar los artefactos de estilo.

<style>
    @media print {
        /* avoid cutting tr's in half */
        th div, td div {
            margin-top:-8px;
            padding-top:8px;
            page-break-inside:avoid;
        }
    }
</style>
<script>
    $(document).ready(function(){
        // Wrap each tr and td's content within a div
        // (todo: add logic so we only do this when printing)
        $("table tbody th, table tbody td").wrapInner("<div></div>");
    })
</script>

Los ajustes de margen y relleno fueron necesarios para compensar algún tipo de inquietud que se estaba introduciendo (supongo, desde bootstrap). No estoy seguro de presentar una nueva solución de las otras respuestas a esta pregunta, pero creo que quizás esto ayude a alguien.

Aaron
fuente
1

Enfrenté el mismo problema y busqué una solución en todas partes, por fin, encontré algo que me funciona para todos los navegadores.

html {
height: 0;
}

use este CSS o en lugar de CSS puede tener este JavaScript

$("html").height(0);

Espero que esto funcione para ti también.

Arrendajo
fuente
0

Revisé muchas soluciones y nadie funcionaba bien.

Así que probé un pequeño truco y funciona:

pie con estilo:position: fixed; bottom: 0px; se coloca en la parte inferior de la última página, pero si el pie de página es demasiado alto, se superpone con el contenido de la tabla.

pie con solo: display: table-footer-group; no se superpone, pero no está en la parte inferior de la última página ...

Pongamos dos pies:

TFOOT.placer {
  display: table-footer-group;
  height: 130px;
}

TFOOT.contenter {
  display: table-footer-group;
  position: fixed;
  bottom: 0px;	
  height: 130px;
}
<TFOOT  class='placer'> 
  <TR>
    <TD>
      <!--  empty here
-->
    </TD>
  </TR>
</TFOOT>	
<TFOOT  class='contenter'> 
  <TR>
    <TD>
      your long text or high image here
    </TD>
  </TR>
</TFOOT>

Uno reserva lugar en las últimas páginas, el segundo pone en su pie de página.

Zenon K.
fuente
-1

He probado todas las sugerencias anteriores y he encontrado una solución de navegador cruzado simple y funcional para este problema. No hay estilos ni saltos de página necesarios para esta solución. Para la solución, el formato de la tabla debería ser como:

<table>
    <thead>  <!-- there should be <thead> tag-->
        <td>Heading</td> <!--//inside <thead> should be <td> it should not be <th>-->
    </thead>
    <tbody><!---<tbody>also must-->
        <tr>
            <td>data</td>
        </tr>
        <!--100 more rows-->
    </tbody>
</table>

Formato anterior probado y funcionando en navegadores cruzados

Ananth Doss
fuente
-2

Bueno chicos ... La mayoría de las soluciones aquí arriba no funcionaron. Así es como las cosas funcionaron para mí ...

HTML

<table>
  <thead>
   <tr>
     <th style="border:none;height:26px;"></th>
     <th style="border:none;height:26px;"></th>
     .
     .
   </tr>
   <tr>
     <th style="border:1px solid black">ABC</th>
     <th style="border:1px solid black">ABC</th>
     .
     .
   <tr>
  </thead>
<tbody>

    //YOUR CODE

</tbody>
</table>

El primer conjunto de encabezado se utiliza como un simulado para que no falte un borde superior en el segundo encabezado (es decir, el encabezado original) durante el salto de página.

Aneesh
fuente
-3

La respuesta aceptada no funcionó para mí en todos los navegadores, pero el siguiente CSS me funcionó:

tr    
{ 
  display: table-row-group;
  page-break-inside:avoid; 
  page-break-after:auto;
}

La estructura html fue:

<table>
  <thead>
    <tr></tr>
  </thead>
  <tbody>
    <tr></tr>
    <tr></tr>
    ...
  </tbody>
</table>

En mi caso, hubo algunos problemas adicionales con el thead tr, pero esto resolvió el problema original de evitar que las filas de la tabla se rompieran.

Debido a los problemas de encabezado, finalmente terminé con:

#theTable td *
{
  page-break-inside:avoid;
}

Esto no evitó que las filas se rompieran; solo el contenido de cada celda.

David Moeller
fuente