Comment gérer les sauts de page lors de l'impression d'un grand tableau HTML

261

J'ai un projet qui nécessite l'impression d'un tableau HTML avec plusieurs lignes.

Mon problème est la façon dont le tableau est imprimé sur plusieurs pages. Il coupera parfois une ligne en deux, ce qui la rendra illisible car une moitié se trouve sur le bord saignant d'une page et le reste est imprimé en haut de la page suivante.

La seule solution plausible à laquelle je peux penser est d'utiliser des DIVs empilés au lieu d'un tableau et de forcer les sauts de page si nécessaire .. mais avant de passer par tout le changement, je pensais pouvoir demander ici avant.

h3.
la source
28
Sur une tangente, il peut être utile d'ajouter un <thead>à votre tableau avec le CSS suivant thead {display: table-header-group; }afin d'imprimer l'en-tête du tableau sur toutes les pages suivantes (utile pour les tableaux de données loooooong).
David dit de réintégrer Monica

Réponses:

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
la source
18
Cela échoue également dans les navigateurs WebKit (par exemple, Safari et Chrome)
Michael Haren
5
Bien qu'il s'agisse de la manière conforme aux normes de le faire, le seul navigateur qui implémente actuellement la norme est Opera. Notez que cela fait partie de css2, et donc le manque d'implémentation sera probablement un problème pendant un certain temps à venir, car apparemment personne ne s'en soucie.
pkh
16
La spécification CSS 2.1 indique que les attributs de style de saut de page ne sont appliqués qu'aux éléments de niveau bloc. Le mode d'affichage par défaut des lignes du tableau est tableau-ligne. Malheureusement, aucun élément de table n'est un élément de niveau bloc par défaut, y compris la table elle-même.
lsuarez
2
@ SinanÜnür Ce n'est pas une exigence, vous ne pouvez donc pas vous y fier, et malheureusement, d'après mes tests, je peux voir que le webkit a vu "peut" et ignoré tout ce qui le dépassait. Étrangement, IE a un support d'impression de grande table plutôt sympa. Je n'ai jamais pensé chanter ses louanges sur un point donné.
lsuarez
6
Je peux confirmer que cela ne fonctionne PAS correctement dans Chrome ou tout autre navigateur Webkit (par exemple Safari, Opera) - à moins que, par "fonctionne bien", vous vouliez dire "exclut toutes les fonctionnalités considérées comme facultatives". Je pense que ce que la plupart des gens veulent, c'est exécuter des en-têtes et des pieds de page, et des tableaux qui n'autorisent que les sauts de page entre les lignes, dont aucun n'est implémenté dans Webkit à partir du 2015/11/13.
DoctorDestructo
47

Remarque: lorsque vous utilisez le saut de page: toujours pour la balise, il créera un saut de page après le dernier bit du tableau, créant une page entièrement vierge à la fin à chaque fois! Pour résoudre ce problème, remplacez-le par saut de page: auto. Il se cassera correctement et ne créera pas une page vierge supplémentaire.

<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
la source
Fonctionne pour moi sur Chrome et est une belle solution CSS simple.
Ryan
1
J'essaie la même solution, mais elle ne casse pas les données de la table et ne fait pas disparaître les données supplémentaires au lieu de les afficher sur la page suivante. Des suppositions?
Null Pointer
24

Extension de la solution 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>

Il semble que page-break-inside:avoiddans certains navigateurs, seuls les éléments de bloc sont pris en compte, pas les cellules, les tableaux, les lignes ni les blocs en ligne.

Si vous essayez d' utiliser display:blockla TRbalise et que vous l'utilisez page-break-inside:avoid, cela fonctionne, mais vous vous trompez avec la disposition de votre table.

vicenteherrera
la source
2
Voici un moyen facile d'ajouter dynamiquement les divs avec jquery:$(document).ready(function(){$("table tbody th, table tbody td").wrapInner("<div></div>");});
Chris Bloom
1
Merci à sinan ürün, vicenteherrera et Chrisbloom7. J'ai appliqué la combinaison de vos réponses et ça marche maintenant!
Nurhak Kaya
Vous pouvez essayer de définir le @media CSS sur tr { display: block; }pour l'impression uniquement, plutôt que d'ajouter tous les <div>éléments étrangers . (N'ont pas été testés mais valent le détour)
Stephen R
11

Aucune des réponses ici n'a fonctionné pour moi dans Chrome. AAverin sur GitHub a créé du Javascript utile à cet effet et cela a fonctionné pour moi:

Ajoutez simplement le js à votre code et ajoutez la classe 'splitForPrint' à votre tableau et il divisera soigneusement le tableau en plusieurs pages et ajoutera l'en-tête du tableau à chaque page.

MDave
la source
Avez-vous un exemple sur la façon de l'appliquer? J'ai essayé d'assigner ma table className as splitForPrintmais dans le JS il n'y a nulle part où il a pris la référence de l'élément en utilisant le className splitForPrint. Seule la partie où var splitClassName = 'splitForPrint';mais c'est tout.
Compaq LE2202x
Voté parce que le script auquel vous avez lié ne résout pas le problème de l'OP sans une sélection et une reconfiguration considérables, et vous n'avez fourni aucun exemple de la façon dont on pourrait s'y prendre.
Chris Bloom,
A fonctionné comme un charme pour moi, aucune des autres solutions n'a fonctionné. +1 J'ai dû ajouter un petit css pour obtenir les pauses correctes .page-break {page-break-after: toujours; }
fhugas
Oui, en ajoutant .page-break {page-break-after: toujours; } ça m'a sauvé la journée!
milodky
7

Utilisez ces propriétés CSS:

page-break-after

page-break-before 

Par exemple:

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

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

via

marcgg
la source
Je ne suis pas sûr, vous devrez vérifier. Sinon, divisez-les en différents tableaux et séparez les tableaux par un div vide
marcgg
Vous devrez l'appliquer à la ligne du tableau ou même à la cellule, mais pas au tableau, je pense. A part ça, ça devrait marcher.
Pekka
2
ne fonctionne pas en chrome. Est ignoré comme si 13/06/2012 lors de l'application à TR
ladieu
5

J'ai récemment résolu ce problème avec une bonne solution.

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

Fonctionne comme un charme!

Wendel Tavares
la source
2

J'ai fini par suivre l'approche de @ vicenteherrera, avec quelques ajustements (qui sont peut-être spécifiques au bootstrap 3).

Fondamentalement; nous ne pouvons pas casser trs ou tds car ce ne sont pas des éléments de niveau bloc. Nous avons donc incorporé divs dans chacun, et appliquer nos page-break-*règles contre le div. Deuxièmement; nous ajoutons un rembourrage en haut de chacune de ces divs, pour compenser les artefacts de style.

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

Les ajustements de marge et de remplissage étaient nécessaires pour compenser une sorte de gigue qui était introduite (à mon avis - à partir du bootstrap). Je ne suis pas sûr de présenter une nouvelle solution à partir des autres réponses à cette question, mais je pense que cela aidera peut-être quelqu'un.

Aaron
la source
1

J'ai fait face au même problème et je cherche partout une solution, enfin, je trouve quelque chose qui fonctionne pour moi pour tous les navigateurs.

html {
height: 0;
}

utilisez ce css ou au lieu de css vous pouvez avoir ce javascript

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

J'espère que cela fonctionnera aussi pour vous.

Geai
la source
0

J'ai vérifié de nombreuses solutions et tout le monde ne fonctionnait pas bien.

J'ai donc essayé un petit truc et ça marche:

tfoot with style: position: fixed; bottom: 0px; est placé en bas de la dernière page, mais si le pied de page est trop haut, il est superposé par le contenu du tableau.

tfoot with only: display: table-footer-group; n'est pas superposé, mais n'est pas en bas de la dernière page ...

Mettons deux tfoot:

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>

Une réserve de place sur les dernières pages, la seconde met votre pied de page accual.

Zenon K.
la source
-1

J'ai essayé toutes les suggestions ci-dessus et trouvé une solution de navigateur croisé simple et fonctionnelle pour ce problème. Aucun style ni saut de page n'est nécessaire pour cette solution. Pour la solution, le format du tableau doit être comme:

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

Format ci-dessus testé et fonctionnant dans les navigateurs croisés

Ananth Doss
la source
-2

Eh bien les gars ... La plupart des solutions ici n'ont pas fonctionné. Voilà comment les choses ont fonctionné pour moi ..

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>

Le premier jeu de têtes est utilisé comme factice afin qu'il n'y ait pas de bordure supérieure manquante dans la 2ème tête (c'est-à-dire la tête d'origine) pendant le saut de page.

Aneesh
la source
-3

La réponse acceptée n'a pas fonctionné pour moi dans tous les navigateurs, mais le CSS suivant a fonctionné pour moi:

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

La structure html était:

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

Dans mon cas, il y avait quelques problèmes supplémentaires avec le thead tr, mais cela a résolu le problème d'origine de garder les lignes du tableau de se casser.

En raison des problèmes d'en-tête, je me suis finalement retrouvé avec:

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

Cela n'a pas empêché les lignes de se casser; juste le contenu de chaque cellule.

David Moeller
la source