So vermeiden Sie Seitenumbrüche in Tabellenzeilen für wkhtmltopdf

79

Ich generiere einen PDF-Bericht von einer HTML-Seite mit einer Tabelle .

Ich benutze wkhtmltopdf für diesen Zweck.

Wenn PDF generiert wird, wird es an einer beliebigen Stelle im tr-Tag unterbrochen .

Ich möchte es vermeiden.

Mohammad Sadiq Shaikh
quelle

Antworten:

147

Update 17.09.2015: Überprüfen Sie die Version, die Sie verwenden: wkhtmltopdf 0.12.2.4 soll das Problem beheben (ich habe nicht überprüft) .


Dies ist ein bekanntes Problem in wkhtmltopdf. Der vom Webkit verwendete Seitenumbruchalgorithmus (der WK in WKhtmltopdf) funktioniert für große Tabellen nicht wirklich gut. Ich schlage vor, die Tabelle in kleinere Teile aufzuteilen, die sich leichter in Seiten aufteilen lassen und das CSS häufig verwenden:

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

Schauen Sie sich auch die folgenden wkhtmltopdf-Probleme an. Sie enthalten interessante Kommentare, in denen beispielsweise das Problem der Tabellenaufteilung erläutert wird. Es gibt eine JS-Lösung, die Tabellen in 168 programmgesteuert aufteilt, was Ihnen helfen könnte (ich verwende sie jedoch nicht).

Update 08.11.2013 In der oben verlinkten Ausgabe 168 wird viel darüber diskutiert. Jemand hat es geschafft, eine Version von wkhtmltopdf zu kompilieren, die ein besseres Tabellenbrechen unterstützt, aber leider scheint es, dass es nicht offiziell veröffentlicht wurde und möglicherweise andere Fehler enthält. Ich weiß nicht, wie ich es bekommen soll und ich weiß nicht, wie ich es unter Windows kompilieren soll, aber jeder Interessierte kann zum Beispiel den Kommentar hier überprüfen (siehe neues Update unten).

Update 24.02.2014 Sie werden erfreut sein zu hören, dass in wkhtmltopdf 0.12 diese Funktion unter anderem stark verbessert wurde. Warten Sie jedoch auf 0.12.1 und testen Sie es gründlich, bevor Sie eine neue Version verwenden. Es ist immer noch ein wenig instabil, obwohl die neuen Leute, die mit Antialize arbeiten, einen großartigen Job machen (Ashkulz Rocks)! Halten Sie sich unter wkhtmltopdf.org und github auf dem Laufenden . Die Google Code-Site ist veraltet und wird langsam migriert.

Joel Peltonen
quelle
1
Danke für die Auskunft. Version 0.12.1 löst das Problem mit dem Seitenumbruch.
Nidhi Sarvaiya
1
Beachten Sie, dass diese Lösung nur mit der aktuellen Version 0.12.1 funktioniert. Alles frühere funktioniert immer noch nicht.
Cerin
4
Ich hatte ein paar Tage damit zu kämpfen. Es stellte sich heraus, dass mein Tisch in einem Div mit einem Stil von war display: inline-block. Geändert zu blockund mit den Änderungen darüber fing alles an zu funktionieren!
Hugh
2
@Nenotlep danke für deine Antwort. Ja, ich habe bereits eine neue Frage dazu gestellt: stackoverflow.com/q/36334330/3391783 - es ist lustig, wie dies alles in Versionen mit 0.12.1-ish oder 0.12.2-ish zu funktionieren schien und in 0.12 wieder kaputt ist. 3-ish Versionen.
low_rents
2
@DjDacSaunders WKHTMLTOPDF ist ein Hack, kein reines HTML -> PDF-Tool. Der Zweck besteht darin, ein sehr langes Dokument in ein Seitenformat zu rendern. Die Tatsache, dass wir die Kontrolle darüber haben, ist großartig. Wenn Sie möchten, dass dies verbessert wird, ist der vorgelagerte Ort für wkhtml der absolut beste Kontaktpunkt. Dies ist entweder das QT-Projekt oder möglicherweise das WebKit-Projekt. Ich gehe davon aus, dass sich dieses Ding nie ändert, da es nicht wirklich das ist, was WebKit beim Rendern von Webseiten als PDF-Dateien tun sollte: / Versuchen Sie zur vollständigen Kontrolle vielleicht PrinceXML. (x) HTML ist kein Druckformat und "Lösungen" für dieses Problem sind immer Hacks.
Joel Peltonen
18

Es ist ein alter Beitrag, aber da ich viel Zeit damit verschwendet habe, eine richtige Lösung zu finden, werde ich ihn hier einfügen, vielleicht ist er für jemanden nützlich.

Also von dem, was ich gelesen habe, das Problem mit

page-break-inside: avoid

ist, dass es nicht funktioniert. Aber tatsächlich, wenn Sie es auf ein Element setzen, das display:blockes hat , funktioniert es wie erwartet (wie irgendwo in SO angegeben). also für einfache strukturierung der tabelle css mit

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

und Tabellenstruktur

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

wird wie erwartet funktionieren.

Ich hatte einen etwas komplizierteren Fall mit Reihenspannen, daher brach die Lösung von oben in Stücke, was nicht erwünscht war. Ich habe es mit divs für jeden zeilenübergreifenden Satz von Zeilen gelöst. Meine jquery macht den ganzen Job:

$(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;
}

Ich weiß nicht, ob alles gebraucht wird und ich denke nicht, dass es perfekt ist, aber es macht den Job. Nur auf Chrom getestet

interner Serverfehler
quelle
16

Seit 0.12 wurde dieses Problem behoben, aber manchmal, wenn eine Tabelle zu lang ist, um in die Seite zu passen, zerlegt wkhtmltopdf sie in zwei Teile und wiederholt die Spaltenüberschriften auf der neuen Seite, und diese Spaltenüberschriften werden der ersten Zeile überlagert.

Ich fand eine zeitliche Lösung für dieses Problem im Abschnitt wkhtmltopdf Github-Probleme: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2531

Fügen Sie einfach diese Zeilen zu Ihrer Ansicht CSS hinzu:

tr {
  page-break-inside: avoid; 
}
Nacho Moço
quelle
Das hilft tatsächlich. Vielen Dank!! Nicht sicher, warum dies nicht das Standardverhalten ist.
JosephK
6

Ich habe mich tagelang mit diesen Problemen befasst und endlich die perfekte Lösung gefunden. Sie können auf dieses Projekt phpwkhtmltopdf verweisen . Schauen Sie in das Verzeichnis articleund Sie werden 3 Lösungen für 3 Probleme finden. Kurz gesagt, die ultimative Lösung ist das Hinzufügen des CSS-Stils

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

Wenn Sie Chinese sind, können Sie diese Seite gerne besuchen. Schauen Sie sich das Wesentliche an, wenn Sie das Wesentliche für wkhtmltopdf wünschen

UnixAgain
quelle
Das hat bei mir funktioniert. Ich benutze wkhtmltopdf 0.12.4 . Vielen Dank!
Hugo
Genial, das hat es für mich getan. Vielen Dank!!!
Fafafooey
5

Ich habe festgestellt, dass ab wkhtmltopdf 0.12.2.1 dieses Problem behoben wurde.

York Mak
quelle
7
Das ist nicht wahr. Wir haben immer noch das Problem.
Niklas R.
1
Und das sollte nur ein Kommentar sein.
Wesley Brian Lachenal
5

In meinem speziellen Fall hat aus irgendeinem Grund keine der vorherigen Antworten für mich funktioniert. Was letztendlich funktionierte, war eine Kombination aus mehreren Dingen.

  1. Ich installierte (in Ubuntu 16.04) der wkhtmltopdf Python - Wrapper namens PDFKit PIP3 verwenden, und dann anstelle wkhtmltopdf über installieren apt-get ich die statische binäre (Version 0.12.3) installiert anhand der folgenden Skript, von hier genommen

    #!/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. Dieses CSS wurde hinzugefügt (wie in einer der Antworten hier vorgeschlagen):

    tr, td div, th div{
        page-break-inside: avoid;
    }
    
  3. Und dann auch noch hinzufügen <thead>und <tbody>markieren, wie hier vorgeschlagen (ohne diese würde die Tabelle immer noch auf hässliche Weise brechen):

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

Mit diesen Änderungen kann ich nun erfolgreich Mako-Vorlagen verwenden , um den HTML-Code zu generieren und diesen dann an Wkhtmltopdf weiterzuleiten und ein wunderschön paginiertes PDF zu erhalten.

Acapulco
quelle
4

Ich habe alle Arten von Manipulationen an meinen Tabellen versucht, aber nichts, was ich versucht habe, konnte verhindern, dass die Seitenumbrüche in die Mitte einer Zeile gestellt werden. In meiner Verzweiflung habe ich verschiedene Versionen ausprobiert und Folgendes gefunden:

Wkhtmltopdf 0.12.2.1: Schlecht

Wkhtmltopdf 0.12.3: Schlecht

Wkhtmltopdf 0.12.1: Gut

Meine Lösung bestand darin, ein Downgrade auf Version 0.12.1 durchzuführen, wodurch meine Probleme gelöst wurden. Zugegeben, sie könnten teilweise darauf zurückzuführen sein, dass mein HTML-Code keine Super-OCD ist, aber da der HTML-Code in TinyMCE (von Benutzern) generiert wird, habe ich nicht wirklich eine große Auswahl.

Außerdem funktionieren verschachtelte Tabellen in keiner Version für mich.

Ben Hitchcock
quelle
für mich löst 0.12.1 das Problem nicht und es nimmt toc weg
UnixAgain
2

Ich hatte das gleiche Problem. Fügen Sie nach vielen Versuchen und Fehlern hinzu, dass dieses CSS das Problem gelöst hat

tr { display: inline-table; }

akhilesh.saipangallu
quelle
2

Wie verwende ich Seitenumbrüche in PDF, ohne ein tr zu brechen?

Hier ist eine Lösung, die Sie in jeder HTML-Datei verwenden können .....

Nachdem Sie Ihr tr gestartet haben, müssen Sie ein div innerhalb des tr nehmen und dieses CS dem div geben:

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

Die obigen Antworten haben bei mir nicht funktioniert. Ich musste die Zoomoption meiner pdfkit-Konfiguration speziell deaktivieren.

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

Für alle, die immer noch Probleme damit haben, ist es wichtig, sich daran zu erinnern, dass der Tisch ein direktes Kind des Körpers sein muss , sonst funktioniert das CSS nicht (zumindest ist das bei mir passiert).

Luccas Correa
quelle
Dies war nicht der Fall für mich - ich kann bestätigen, dass sogar verschachtelte Tabellen die Seitenumbrüche respektierten ... das Problem für mich war mehr Mac OS gegen Ubuntu ...
Petrov
Ich hatte ein ähnliches Problem: Mein Tisch befand sich innerhalb eines Div mit display: table-cell;angewendet. Wenn Sie diese Stile @media only screenkorrigieren, werden die Seitenumbrüche behoben. Wenn Sie keine Seitenumbrüche erzielen können, versuchen Sie zu teilen und zu erobern, indem Sie die Hälfte des CSS schrittweise entfernen und prüfen, ob es funktioniert.
Leslie Viljoen
1

Ich habe diese lächerliche Lösung gefunden, aber sie hat bei mir sehr gut funktioniert :)

Ich habe gerade eine sehr lange Rowspan-Spalte wie diese eingefügt

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

und dann würde der Tisch nicht brechen.

aswzen
quelle
1

Eine weitere Option: Platzieren Sie jede trfür sich tbodyund wenden Sie dann die CSS-Regeln für die Pausenunterbrechung auf die an tbody. Tabellen unterstützen mehrere tbodys.

Ein bisschen extra Markup, funktioniert aber anständig für mich.

Troy Morehouse
quelle
Ich habe dies an einer Gruppe von tr-Elementen versucht - indem ich sie in separate tbody-Elemente eingeschlossen habe -, um zu versuchen, bestimmte Gruppen von Zeilen zusammenzuhalten. Es hatte keine Wirkung. Führen Sie diese Methode ohne "Seitenumbruch: Vermeiden" aus. Beim Element "tr" wurde erneut das Drucken von Daten über den Seitenkopfzeilen rückgängig gemacht (das "Standard" -Verhalten).
JosephK
Ja, ich wende jetzt die gleiche Regel "Seitenumbruch innen: Vermeiden" sowohl für tbody als auch für tr und td an: "tbody, tbody> tr, tbody> tr> td, tbody> tr> th {Seitenumbruch innen: vermeiden;} ", was in den meisten Situationen zu funktionieren scheint.
Troy Morehouse
Danke, aber ich habe es gerade versucht. Es bricht immer noch in der Mitte meiner Gruppen von Tabellenzeilen. Ich habe auch versucht, dem tbody eine Klasse hinzuzufügen und der Klasse mit dem 'Vermeiden' CSS zuzuweisen - keine Auswirkung. Ich wünschte, ich wüsste, was dies tatsächlich mit der CSS-Regel "macht" - vielleicht eine Möglichkeit, um zu glauben, dass eine Gruppe von Trs wirklich "eine Reihe" ist -, aber da das Erstellen eines Tr 2x + groß es auch bricht, schätze ich nicht. Vielleicht wird jemand in weiteren 10 Jahren eine brauchbare HTML-zu-PDF-Lösung erstellen, aber ich denke, er wartet stattdessen auf die direkte neuronale Datenübertragung.
JosephK
1

Ich habe das Problem mit einer Kombination einiger Lösungsvorschläge gelöst.

Ich habe meine Tabelle in ein div eingewickelt und das folgende CSS definiert.

.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;
    }

Die Tabellenstruktur wurde nach Abschluss wie folgt definiert:

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

Ich musste kein Div innerhalb der td- oder th-Tags erstellen.

Wichtige Dinge, die mir beim Versuch, das Problem zu lösen, aufgefallen sind:

  • Der Körper muss in der Tabelle enthalten sein
  • Das div muss display: block haben
  • Wenn eine Tabelle nicht in eine Seite passt, wird automatisch die gesamte Tabelle auf die nächste Seite verschoben (ich habe diese nicht mit großen Tabellen ausprobiert).
  • Wenn Sie nur den Selektor ".wrapping-div table" aus dem CSS entfernen , kann die Tabelle auf zwei Seiten aufgeteilt werden, wird jedoch korrekt gerendert , ohne dass eine Zelle auf zwei Seiten aufgeteilt wird (dies entspricht dem Standardverhalten in Word) )

Ich hoffe das hilft.

Tiago Freitas
quelle
1

Um Seitenumbrüche zu vermeiden, können wir die Option "Seitenumbrüche vermeiden" verwenden.

tr { page-break-inside: avoid; }

Brechen Sie alle Inhalte (Bild / Text) und lassen Sie sie auf der nächsten Seite erscheinen

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

Hast du einen Tischkopf? und ein Tischkörper?

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

Das ist die richtige Formatierung einer Tabelle, während es die meisten Browser nicht weniger interessieren könnten, Konverter wie der von Ihnen erwähnte können, wenn Ihre fehlenden <tbody>oder <th>Tags, ich schlage vor, Sie versuchen, diese zuerst hinzuzufügen.

suicidal.banana
quelle