Cómo evitar el salto de página dentro de la fila de la tabla para wkhtmltopdf

81

Estoy generando un informe en pdf desde una página html con una tabla .

Estoy usando wkhtmltopdf para este propósito.

cuando se genera pdf, se rompe en cualquier lugar de la etiqueta tr .

Quiero evitarlo.

Mohammad Sadiq Shaikh
fuente

Respuestas:

152

Actualización 17.09.2015: Verifique la versión que está utilizando: se dice que wkhtmltopdf 0.12.2.4 soluciona el problema (no lo he verificado) .


Este es un problema conocido en wkhtmltopdf. El algoritmo de salto de página utilizado por webkit (el WK en WKhtmltopdf) no funciona realmente bien para tablas grandes. Sugiero dividir la tabla en partes más pequeñas que se dividen más fácilmente en páginas y usar mucho el CSS:

table, tr, td, th, tbody, thead, tfoot {
    page-break-inside: avoid !important;
}

También eche un vistazo a los siguientes problemas de wkhtmltopdf, tienen comentarios interesantes que discuten, por ejemplo, el problema de división de tablas. Hay una solución JS que divide las tablas programáticamente en 168 que podría ayudarlo (aunque no la uso).

Actualización 08.11.2013 Hay mucha discusión sobre esto en el número 168 vinculado anteriormente. Alguien ha logrado compilar una versión de wkhtmltopdf que admite una mejor división de tablas, pero desafortunadamente parece que no se lanzó oficialmente y podría contener otros errores. No sé cómo obtenerlo y no sé cómo compilar en Windows, pero cualquier persona interesada puede consultar, por ejemplo, el comentario aquí. (ver nueva actualización a continuación).

Actualización 24.02.2014 Le complacerá saber que en wkhtmltopdf 0.12 esta función, entre otras, se ha mejorado considerablemente. Sin embargo, espere 0.12.1 y pruebe a fondo antes de comenzar a usar cualquier versión nueva, todavía es un poco inestable, aunque los nuevos chicos que están trabajando con antialize están haciendo un gran trabajo (ashkulz rocks). Manténgase actualizado en wkhtmltopdf.org y github . El sitio de código de Google está obsoleto y se está migrando lentamente.

Joel Peltonen
fuente
1
Gracias por la información. La versión 0.12.1 resuelve el problema de los saltos de página.
Nidhi Sarvaiya
1
Tenga en cuenta que esta solución solo funciona con la versión 0.12.1 reciente. Cualquier cosa anterior todavía no funciona.
Cerin
4
Luché con esto durante un par de días. Resultó que mi mesa estaba en un div con un estilo de display: inline-block. ¡Lo cambié a blocky el con los cambios encima de todo comenzó a funcionar!
Hugh
2
@Nenotlep gracias por tu respuesta. sí, ya publiqué una nueva pregunta sobre esto: stackoverflow.com/q/36334330/3391783 - es curioso cómo todo esto parecía funcionar en las versiones 0.12.1-ish o 0.12.2-ish y se rompe nuevamente en 0.12. Versiones 3-ish.
low_rents
2
@DjDacSaunders WKHTMLTOPDF es un truco, no una herramienta html pura -> pdf. El objetivo es convertir un documento muy largo en un formato paginado. El hecho de que tengamos algún control sobre esto es genial. Si desea que esto mejore, el mejor lugar para contactar es el upstream de wkhtml, que es el proyecto QT o quizás el proyecto WebKit. Preveo que esto nunca cambiará, ya que no es realmente lo que WebKit estaba destinado a hacer al representar páginas web como archivos PDF: / Para un control total, quizás pruebe PrinceXML. (x) HTML no es un formato de impresión y las "soluciones" a ese problema son siempre trucos.
Joel Peltonen
18

Es una publicación antigua, pero como estaba perdiendo mucho tiempo tratando de encontrar una solución adecuada, la pondré aquí, tal vez sea útil para alguien.

Entonces, por lo que leí, el problema con

page-break-inside: avoid

es que no funciona. Pero en realidad, si lo configura en un elemento que tiene display:block, funciona como se esperaba (como se indica en algún lugar de SO). así que para una estructura simple de la tabla css con

td div, th div{
    page-break-inside: avoid;
}

y estructura de la mesa

<table>
....
<tr>
    <td><div>some text</div></td>
    <td><div>more text</div></td>
</tr>
....
</table>

funcionará como se esperaba.

Tenía un caso un poco más complicado con los intervalos de filas, por lo que la solución de arriba fue romperlo en pedazos, lo que no era el efecto deseado. Lo resolví usando divs para cada conjunto de líneas en filas. Mi jquery js hace todo el trabajo:

$(window).load(function () {
    var sizes = {};
    $('#the_table tr:first th').each(function (a, td) {         
        var w = $(td).width();
        if (sizes.hasOwnProperty('' + a)) {
            if (sizes['' + a] < w)
                sizes['' + a] = w;
        }
        else {
            sizes['' + a] = w;
        }
    });

    var tableClone = $('#the_table').clone();
    $('#the_table').replaceWith('<div class="container"></div>');

    var curentDivTable;
    var cDiv = $('.container');
    tableClone.find('tr').each(function (i, ln) {
        var line = $(ln);
        if (line.hasClass('main_row')) {
            var div = $('<div class="new-section"><table><tbody>')
            currentDivTable = div.find('tbody');
            cDiv.append(div);               
        }
        currentDivTable.append(line);
    });
    //optional - maybe in % its better than px
    var sum = 0;
    $.each(sizes, function (a, b) {
        sum += b;
    });
    var widths = {};
    $.each(sizes, function (a, b) {
        var p = Math.ceil(b * 100 / sum);
        widths['' + a] = p + '%';
    });
    //setup
    $('.container table').each(function (a, tbl) {
        $(tbl).find('tr:first td, tr:first th').each(function (b, td) {
            $(td).width(widths['' + b]);
        });
        $(tbl).addClass('fixed');
    });
});

css:

div.new-section {
    page-break-inside: avoid;
}
.container, .new-section, .new-section table.fixed{
    width: 100%;
}

.new-section table.fixed{
    table-layout:fixed;
}

No sé si todo es necesario y no creo que sea perfecto, pero funciona. Probado solo en cromo

error de servidor interno
fuente
16

Desde 0.12, este problema se ha resuelto pero, a veces, cuando una tabla es demasiado larga para caber en la página, wkhtmltopdf la divide en dos partes y repite los encabezados de columna en la nueva página y estos encabezados de columna aparecen superpuestos a la primera fila.

Encontré una solución temporal a este problema en la sección de problemas de github wkhtmltopdf: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2531

Simplemente agregue estas líneas a su vista css:

tr {
  page-break-inside: avoid; 
}
Nacho Moço
fuente
Esto realmente ayuda. ¡¡Gracias!! No estoy seguro de por qué este no es el comportamiento predeterminado.
JosephK
6

He investigado estos problemas durante días y finalmente encontré la solución perfecta. Puede hacer referencia a este proyecto phpwkhtmltopdf . Busque en el directorio articley encontrará 3 soluciones para 3 problemas. En resumen, la solución definitiva es agregar el estilo CSS

thead {
    display: table-row-group;
}
tr {
    page-break-before: always;
    page-break-after: always;
    page-break-inside: avoid;
}
table {
    word-wrap: break-word;
}
table td {
    word-break: break-all;
}

Si es chino, no dude en consultar este sitio关于 wkhtmltopdf , 你 一定 想 知道 这些 Consulte la esencia si desea la esencia de wkhtmltopdf

Unix de nuevo
fuente
Esto funcionó para mí. Estoy usando wkhtmltopdf 0.12.4 . ¡Gracias!
Hugo
5

Descubrí que wkhtmltopdf 0.12.2.1 en adelante ha solucionado este problema.

York Mak
fuente
7
Eso no es cierto. Todavía tenemos el problema.
Niklas R.
1
Y esto debería ser solo un comentario.
Wesley Brian Lachenal
5

En mi caso particular, por alguna razón, ninguna de las respuestas anteriores funcionó para mí. Lo que terminó funcionando fue en realidad una combinación de varias cosas.

  1. Instalé (en Ubuntu 16.04) el contenedor de python Wkhtmltopdf llamado pdfkit usando pip3, y luego, en lugar de instalar Wkhtmltopdf a través de apt-get, instalé el binario estático (versión 0.12.3) siguiendo el siguiente script, tomado de aquí

    #!/bin/sh
    
    sudo apt-get install -y openssl build-essential xorg libssl-dev
    wget http://download.gna.org/wkhtmltopdf/0.12/0.12.3/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    tar -xJf wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    cd wkhtmltox
    sudo chown root:root bin/wkhtmltopdf
    sudo cp -r * /usr/
    
  2. Se agregó este CSS (como se sugiere en una de las respuestas aquí):

    tr, td div, th div{
        page-break-inside: avoid;
    }
    
  3. Y luego también agregue etiquetas <thead>y <tbody>como se sugiere aquí también (sin estas, la tabla aún se rompería de una manera fea):

    <table>
        <thead>
            <tr>
                <th>Column 1</th>
                <th>Column 2</th>
            </tr>
        </thead>
    
        <tbody>
            <tr>
                <td>Value 1</td>
                <td>Value 2</td>
            </tr>
        </tbody>
    </table>
    

Con estas modificaciones, ahora puedo usar con éxito las plantillas de Mako para generar el HTML y luego enviarlo a Wkhtmltopdf y obtener un PDF bellamente paginado.

Acapulco
fuente
4

Intenté todo tipo de manipulaciones en mis tablas, pero nada de lo que intenté pudo evitar que los saltos de página se colocaran en el medio de una fila. Desesperado, probé diferentes versiones y encontré lo siguiente:

Wkhtmltopdf 0.12.2.1: Malo

Wkhtmltopdf 0.12.3: Malo

Wkhtmltopdf 0.12.1: Bueno

Mi solución fue cambiar a la versión 0.12.1, que resolvió mis problemas. Por supuesto, es posible que se hayan debido en parte a que no soy un super TOC con mi html, pero como el HTML se genera dentro de TinyMCE (por los usuarios), realmente no tengo muchas opciones.

Además, las tablas anidadas no funcionan en ninguna versión para mí.

Ben Hitchcock
fuente
0.12.1 para mí no resuelve el problema, y se tarda toc distancia
UnixAgain
2

¿Cómo usar saltos de página dentro de PDF sin romper un tr?

Aquí hay una solución que puede usar en cualquier archivo html .....

Después de iniciar su tr, debe tomar un div dentro del tr y darle este css al div:

<tr>
      <div style="page-break-inside:avoid !important; page-break-after:auto !important; overflow: hidden; display:block !important; width:100% ">
     </tr>
Vibha Kachhela
fuente
2

Estaba enfrentando el mismo problema, agregue después de muchas pruebas y errores, este css resolvió el problema

tr {
    display: inline-table;
}
akhilesh.saipangallu
fuente
1

Las respuestas anteriores no me funcionaron. Tuve que deshabilitar específicamente la opción de zoom en mi configuración de pdfkit.

PDFKit.configure do |config|

  config.default_options = {
    print_media_type: false,
    page_size: "A4",
    encoding: "UTF-8",
    ## Make sure the zoom option is not enabled!
    ## zoom: '1.3',
    disable_smart_shrinking: false,
    footer_right: "Page [page] of [toPage]"
  }

end
Hendrik
fuente
1

Para cualquiera que todavía tenga problemas con esto, una cosa para recordar es que la tabla tiene que ser un hijo directo de body , de lo contrario el CSS no funcionará (al menos eso es lo que me pasó a mí).

Luccas Correa
fuente
este no fue el caso para mí, puedo confirmar que incluso las tablas anidadas respetaron los saltos de página ... el problema para mí fue más mac os vs ubuntu ...
Petrov
Tuve un problema similar: mi tabla estaba dentro de un div con display: table-cell;aplicado. Hacer esos estilos @media only screencorrigió los saltos de página. Si no puede hacer que los saltos de página funcionen, intente dividir y conquistar eliminando la mitad del CSS en etapas y ver si funciona.
Leslie Viljoen
1

Encontré esta solución ridícula, pero funcionó muy bien para mí :)

Solo puse una columna de filas muy larga como esta

<td rowspan="XXX TOTAL ROWS" style="width:0px"></td>

y luego la mesa no se rompería.

aswzen
fuente
1

Otra opción: coloque cada uno trpor su cuenta tbodyy luego aplique las reglas css de ruptura de paginación al archivo tbody. Las tablas admiten varios tbodys.

Un poco de marcado adicional, pero funciona decentemente para mí.

Troy Morehouse
fuente
Probé esto en un grupo de elementos tr, envolviéndolos dentro de elementos tbody separados, para tratar de mantener ciertos grupos de filas juntos. No tuvo ningún efecto. Hacer este método sin "page-break-inside: evitar"; en el elemento "tr" provocó una reversión a la impresión de datos en la parte superior de los encabezados de página, nuevamente (el comportamiento "predeterminado").
JosephK
Sí, ahora aplico la misma regla "page-break-inside: evitar" tanto en tbody como en tr y td's: "tbody, tbody> tr, tbody> tr> td, tbody> tr> th {page-break-inside: evitar;} "que parece funcionar en la mayoría de situaciones.
Troy Morehouse
Gracias, pero intenté eso. Todavía hay saltos de página en medio de mis tbody grupos de filas de tablas. También intenté agregar una clase al tbody, y css en la clase con 'evitar', sin efecto. Ojalá supiera lo que realmente estaba "haciendo" con la regla css, tal vez alguna forma de hacer que piense que un grupo de trs es realmente 'una fila', pero como hacer un tr 2x + alto también lo rompe, supongo no. Tal vez alguien cree una solución de HTML a PDF utilizable en otros 10 años, pero creo que, en cambio, está esperando una transferencia directa de datos neuronales.
JosephK
1

Resolví el problema usando una combinación de algunas soluciones sugeridas.

Envolví mi tabla en un div y definí el siguiente CSS.

.wrapping-div {
        display: block;
        page-break-inside: avoid !important;
    }

.wrapping-div table, .wrapping-div tbody, .wrapping-div tr, .wrapping-div td, .wrapping-div th {
        page-break-inside: avoid !important;
    }

La estructura de la tabla cuando terminó se definió como el siguiente ejemplo:

<div class="wrapping-div">
 <table>
  <tbody>
   <tr>
    <th>
      header
    </th>
    <td>
      content
    </td>
   </tr>
  </tbody>
 </table>
</div>

No necesitaba crear ningún div dentro de las etiquetas td o th.

Cosas importantes que noté al intentar resolver el problema:

  • El tbody debe estar incluido en la tabla.
  • El div debe tener display: block
  • Cuando una tabla no cabe en una página, automáticamente moverá toda la tabla a la página siguiente (no he probado esta con tablas enormes)
  • Si elimina solo el selector ".wrapping-div table" del CSS, permitirá que la tabla se divida en dos páginas, pero la representará correctamente, sin dividir una celda en dos páginas (es como el comportamiento predeterminado en Word )

Espero que esto ayude.

Tiago Freitas
fuente
1

Para evitar el salto de página, podemos usar la opción de evitar el salto de página de CSS.

tr { page-break-inside: avoid; }

Divida cualquier contenido (imagen / texto) y haga que aparezca en la página siguiente

.sample-image { page-break-before: always; }
Arvind singh
fuente
0

¿Tienes una cabecera de mesa? y un cuerpo de mesa?

<table>
<tbody>
<tr><th>Name</th><th>Value</th></tr>
<tr><td>url</td><td>stackoverflow.com</td></tr>
<tr><td>ip</td><td>123.123.123.123</td></tr>
</tbody>
</table>

Ese es el formato adecuado de una tabla, mientras que a la mayoría de los navegadores no les importa, convertidores como el que mencionas sí, si faltan etiquetas <tbody>o <th>etiquetas, te sugiero que intentes agregarlas primero.

suicida plátano
fuente