How to deal with page breaks when printing a large HTML table

HtmlCssPrintingHtml Table

Html Problem Overview


I have a project which requires printing an HTML table with many rows.

My problem is the way the table is printed over multiple page. It will sometimes cut a row in half, making it unreadable because one half is on the bleeding edge of a page and the remainder is printed on the top of the next page.

The only plausible solution I can think of is using stacked DIVs instead of a table and force page-breaks if needed.. but before going through the whole change I thought I could ask here before.

Html Solutions


Solution 1 - Html

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

Solution 2 - Html

Note: when using the page-break-after:always for the

tag it will create a page break after the last bit of the table, creating an entirely blank page at the end every time! To fix this just change it to page-break-after:auto. It will break correctly and not create an extra blank page.

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

Solution 3 - Html

Expanding from Sinan Ünür solution:

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

It seems that page-break-inside:avoid in some browsers is only taken in consideration for block elements, not for cell, table, row neither inline-block.

If you try to display:block the TR tag, and use there page-break-inside:avoid, it works, but messes around with your table layout.

Solution 4 - Html

None of the answers here worked for me in Chrome. AAverin on GitHub has created some useful Javascript for this purpose and this worked for me:

Just add the js to your code and add the class 'splitForPrint' to your table and it will neatly split the table into multiple pages and add the table header to each page.

Solution 5 - Html

Use these CSS properties:

page-break-after

page-break-before 

For instance:

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

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

via

Solution 6 - Html

I recently solved this problem with a good 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();
}

Works like a charm!

Solution 7 - Html

I ended up following @vicenteherrera's approach, with some tweaks (that are possibly bootstrap 3 specific).

Basically; we can't break trs, or tds because they're not block-level elements. So we embed divs into each, and apply our page-break-* rules against the div. Secondly; we add some padding to the top of each of these divs, to compensate for any styling artifacts.

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

The margin and padding adjustments were necessary to offset some kind of jitter that was being introduced (by my guess - from bootstrap). I'm not sure that I'm presenting any new solution from the other answers to this question, but I figure maybe this will help someone.

Solution 8 - Html

I faced the same problem and search everywhere for a solution, at last, I fount something which works for me for every browsers.

html {
height: 0;
}

use this css or Instead of css you can have this javascript

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

Hope this will work for you as well.

Solution 9 - Html

I checked many solutions and anyone wasn't working good.

So I tried a small trick and it works:

tfoot with style:position: fixed; bottom: 0px; is placed at the bottom of last page, but if footer is too high it is overlapped by content of table.

tfoot with only: display: table-footer-group; isn't overlapped, but is not on the bottom of last page...

Let's put two 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>

One reserves place on non-last pages, second puts in your accual footer.

Solution 10 - Html

I've tried all suggestions given above and found simple and working cross browser solution for this issue. There is no styles or page break needed for this solution. For the solution, the format of the table should be like:

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

Above format tested and working in cross browsers

Solution 11 - Html

The accepted answer did not work for me in all browsers, but following css did work for me:

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

The html structure was:

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

In my case, there were some additional issues with the thead tr, but this resolved the original issue of keeping the table rows from breaking.

Because of the header issues, I ultimately ended up with:

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

This didn't prevent rows from breaking; just each cell's content.

Solution 12 - Html

Well Guys... Most of the Solutions up here didn't worked for. So this is how things worked for me..

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>

The first set of head is used as a dummy one so that there won't be a missing top border in 2nd head(i.e. original head) while page break.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionh3.View Question on Stackoverflow
Solution 1 - HtmlSinan ÜnürView Answer on Stackoverflow
Solution 2 - HtmlJosh PView Answer on Stackoverflow
Solution 3 - HtmlvicenteherreraView Answer on Stackoverflow
Solution 4 - HtmlMDaveView Answer on Stackoverflow
Solution 5 - HtmlmarcggView Answer on Stackoverflow
Solution 6 - HtmlWendel TavaresView Answer on Stackoverflow
Solution 7 - HtmlAaronView Answer on Stackoverflow
Solution 8 - HtmlJayView Answer on Stackoverflow
Solution 9 - HtmlZenon K.View Answer on Stackoverflow
Solution 10 - HtmlAnanth DossView Answer on Stackoverflow
Solution 11 - HtmlDavid MoellerView Answer on Stackoverflow
Solution 12 - HtmlAneeshView Answer on Stackoverflow