web-dev-qa-db-fra.com

Comment éviter les sauts de page dans les lignes d'un tableau pour wkhtmltopdf

Je génère un rapport pdf à partir d'une page html avec n tablea.

J'utilise wkhtmltopdf à cette fin.

quand pdf est généré, il casse n'importe où dans la balise tr.

Je veux l'éviter.

70

Mise à jour du 17.09.2015: Vérifiez la version que vous utilisez: wkhtmltopdf 0.12.2.4 est censé résoudre le problème (je n'ai pas vérifié) .


Ceci est un problème connu dans wkhtmltopdf. L'algorithme de coupure de page utilisé par webkit (le WK dans WKhtmltopdf) ne fonctionne pas vraiment pour les grands tableaux. Je suggère de réduire le tableau en de plus petits morceaux qui sont plus facilement scindés en pages et en utilisant le css beaucoup:

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

Jetez également un coup d'oeil aux problèmes suivants de wkhtmltopdf, ils ont des commentaires intéressants qui traitent par exemple du problème de fractionnement de table. Il existe une solution JS qui divise par programme les tables en 168 qui pourrait vous aider (je ne l’utilise pas cependant).

Mise à jour du 08.11.2013 Il y a beaucoup de discussions à ce sujet dans le numéro 168 lié ci-dessus. Quelqu'un a réussi à compiler une version de wkhtmltopdf qui prend en charge une meilleure décomposition des tables, mais malheureusement, il semble que celle-ci ne soit pas officiellement publiée et pourrait contenir d'autres bogues. Je ne sais pas comment l'obtenir et je ne sais pas comment compiler sous Windows, mais toute personne intéressée peut vérifier par exemple le commentaire ici (voir nouvelle mise à jour ci-dessous).

Mise à jour du 24.02.2014 Vous serez ravi d'apprendre que dans wkhtmltopdf 0.12, cette fonctionnalité, entre autres, a été grandement améliorée. Cependant, attendez 0.12.1 et testez bien avant d’utiliser une nouvelle version, c’est toujours un peu instable bien que les nouveaux gars travaillant avec antialize fassent un excellent travail (ashkulz rock)! Restez à jour à wkhtmltopdf.org et github . Le site de code google est obsolète et est en train de migrer lentement.

128
Nenotlep

C'est un vieux message, mais comme je perdais beaucoup de temps à essayer de trouver la solution appropriée, je vais le mettre ici, peut-être que ce sera utile à quelqu'un.

Donc, d'après ce que j'ai lu, le problème avec

page-break-inside: avoid

c'est que ça ne marche pas. Mais en réalité, si vous le définissez sur un élément qui a display:block _ cela fonctionne comme prévu (comme indiqué quelque part dans SO). donc pour la structure simple de la table css avec

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

et la structure de la table

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

fonctionnera comme prévu.

J'avais un cas un peu plus compliqué avec des rangées, donc la solution d'en haut consistait à la décomposer en morceaux, ce qui n'était pas l'effet recherché. Je l'ai résolu en utilisant divs pour chaque ligne de lignes. Mon jquery js fait tout le boulot:

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

Je ne sais pas si tout est nécessaire et je ne pense pas que ce soit parfait, mais cela fait le travail. Testé sur chrome seulement

17

Depuis la version 0.12, ce problème a été résolu, mais parfois, lorsqu'un tableau est trop long pour tenir dans la page, wkhtmltopdf le divise en deux parties et répète les en-têtes de colonne de la nouvelle page. Ces en-têtes de colonne apparaissent superposés à la première ligne.

J'ai trouvé une solution temporelle à ce problème dans la section des problèmes de github de wkhtmltopdf: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2531

Ajoutez simplement ces lignes à votre vue css:

tr {
  page-break-inside: avoid; 
}
13
Nacho Moço

J'ai trouvé que wkhtmltopdf 0.12.2.1 a résolu ce problème.

6
York Mak

Dans mon cas particulier, pour une raison quelconque, aucune des réponses précédentes n'a fonctionné pour moi. Ce qui a fini par fonctionner était en réalité une combinaison de plusieurs choses.

  1. J'ai installé (dans Ubuntu 16.04) le Wkhtmltopdf python appelé pdfkit en utilisant pip3, puis au lieu d'installer Wkhtmltopdf via apt- get J'ai installé le binaire statique (version 0.12.3) en suivant le script ci-dessous, pris à partir d'ici

    #!/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. Ajout de ce CSS (comme suggéré dans l'une des réponses ici):

    tr, td div, th div{
        page-break-inside: avoid;
    }
    
  3. Et puis aussi ajoutez <thead> et <tbody> balises comme suggéré ici aussi (sans celles-ci, la table se casserait quand même d'une manière laide):

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

Avec ces modifications, je peux maintenant utiliser avec succès modèles Mako pour générer le code HTML, puis le transmettre à Wkhtmltopdf et obtenir un fichier joliment paginé PDF :)

5
Acapulco

J'ai essayé toutes sortes de manipulations sur mes tables, mais rien de ce que j'ai essayé ne pouvait empêcher les sauts de page d'être placés au milieu d'une rangée. En désespoir de cause, j'ai essayé différentes versions et trouvé ce qui suit:

Wkhtmltopdf 0.12.2.1: Mauvais

Wkhtmltopdf 0.12.3: Mauvais

Wkhtmltopdf 0.12.1: Bon

Ma solution a été de passer à la version 0.12.1, ce qui a résolu mes problèmes. Certes, ils sont peut-être dus en partie au fait que mon code HTML ne soit pas super OCD, mais comme le code HTML est généré dans TinyMCE (par les utilisateurs), je n'ai pas vraiment beaucoup de choix.

De plus, les tables imbriquées ne fonctionnent dans aucune version pour moi.

3
Ben Hitchcock

J'ai creusé ces problèmes pendant des jours et j'ai finalement trouvé la solution idéale. Vous pouvez référencer ce projet phpwkhtmltopdf . Regardez dans le répertoire article et vous trouverez 3 solutions à 3 problèmes. En bref, la solution ultime est d’ajouter le style 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 vous êtes Chinois, n'hésitez pas à consulter ce site wkhtmltopdf 定 一定 想 知道 这些 Consultez le Gist si vous le souhaitez Gist for wkhtmltopdf

2
UnixAgain

Comment utiliser les sauts de page dans pdf sans casser une vérité?

Voici une solution que vous pouvez utiliser dans n’importe quel fichier html .....

Après avoir commencé votre tr, vous devez prendre une div à l’intérieur du tr et donner ce css au div:

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

Je faisais face au même problème, ajoutons après beaucoup d’essais n erreurs ce css a résolu le problème

tr { display: inline-table; }

2

Pour ceux qui ont encore des problèmes avec cela, une chose à retenir est que le table doit être un enfant direct de body, sinon le css ne fonctionnera pas (du moins c'est que s'est-il passé avec moi).

1
Luccas Correa

Avez-vous une tête de table? et un corps de table?

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

C’est la bonne mise en forme d’un tableau, alors que la plupart des navigateurs se moquent bien de convertisseurs comme celui que vous mentionnez pouvez, si vos balises <tbody> ou <th> manquantes, je vous suggère d'essayer de les ajouter en premier.

1
suicidal.banana

Avec l’ajout de ce que dit Nanotelep, voici l’implémentation fonctionnelle de l’algorithme manuel de rupture de page de table. https://github.com/AAverin/JSUtils/tree/master/wkhtmltopdfTableSplitHack

1
AAverin

Les réponses ci-dessus ne m'ont pas fonctionné. Je devais désactiver spécifiquement l'option de zoom de ma configuration 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
1
Hendrik

Une autre option: placez chaque tr dans son propre tbody, puis appliquez les règles css de rupture de peage à la tbody. Les tables supportent plusieurs tbodys.

Un peu de balisage supplémentaire, mais fonctionne décemment pour moi.

1
Troy Morehouse

J'ai beaucoup lutté avec le problème, en utilisant la dernière version h4cc/wkhtmltopdf-AMD64 version 0.12.4 et enfin, nous avons réussi à le faire fonctionner en rétrogradant la version du paquet à 0.12.3!

1
emix

J'ai résolu le problème en utilisant une combinaison de solutions suggérées.

J'ai enveloppé ma table dans un div et défini le CSS suivant.

.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 structure de la table une fois terminé a été définie dans l'exemple suivant:

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

Je n'avais pas besoin de créer de div à l'intérieur des balises td ou th.

Choses importantes que j'ai remarquées en essayant de résoudre le problème:

  • Le tbody doit être inclus dans le tableau
  • Le div doit avoir display: block
  • Quand un tableau ne rentre pas dans une page, il va automatiquement déplacer le tableau entier vers la page suivante (je n'ai pas essayé celui-ci avec d'énormes tableaux)
  • Si vous ne supprimez que le sélecteur ". Wrapping-div table" du CSS, la table pourra être scindée en deux pages, mais restituée correctement sans diviser une cellule en deux pages ( c'est comme le comportement par défaut sur Word)

J'espère que ça aide.

1
Tiago Freitas

J'ai trouvé cette solution ridicule, mais ça a très bien fonctionné pour moi :)

Je viens de mettre une très longue colonne rowspan comme celle-ci

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

et alors la table ne se briserait pas.

1
aswzen

Pour éviter un saut de page, nous pouvons utiliser l'option de saut de page pour éviter les CSS.

tr { page-break-inside: avoid; }

Casser n'importe quel contenu (Image/Texte) et le faire apparaître dans le page suivante

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