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

425,204

Solution 1

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

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

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

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

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!

Share:
425,204

Related videos on Youtube

h3.
Author by

h3.

Updated on July 19, 2020

Comments

  • h3.
    h3. almost 4 years

    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.

    • Sikshya Maharjan
      Sikshya Maharjan over 14 years
      On a tangent, it might be worth adding a <thead> to your table with the following css thead {display: table-header-group; } so as to print the table-header on all subsequent pages (useful for loooooong data tables).
  • marcgg
    marcgg over 14 years
    I'm not sure, you'll have to check. If not, split into different arrays and separate the arrays by an empty div
  • Pekka
    Pekka over 14 years
    You will have to apply it to the table row or even cell, but not to the table, I think. Other than that, it should work.
  • daustin777
    daustin777 over 13 years
    This does not work in all browsers. It does seem to work in FireFox 3.6 Mac OS.
  • Michael Haren
    Michael Haren over 12 years
    This also fails in WebKit browsers (eg. Safari and Chrome)
  • mikhail-t
    mikhail-t about 12 years
    only 'thead { display:table-header-group }' css entry works in the latest FF12 and none of them works in Chrome 18+...
  • pkh
    pkh about 12 years
    While this is the standards-compliant way to do this, the only browser that currently implements the standard is Opera. Note that this is part of css2, and so the lack of implementation is likely to be a problem for some time to come, because apparently no-one cares.
  • ladieu
    ladieu about 12 years
    does not work in chrome. Is ignored as if 6/13/2012 when applied to TR
  • lsuarez
    lsuarez over 11 years
    The CSS 2.1 specification indicates that page break style attributes are only applied to block-level elements. The default display mode for table rows is table-row. Unfortunately, no table elements are block level elements by default, including the table itself.
  • silbana
    silbana over 11 years
    @lthibodeaux I see ... "User Agents must apply these properties to block-level elements in the normal flow of the root element. User agents may also apply these properties to other elements, e.g., 'table-row' elements." (emphasis mine).
  • lsuarez
    lsuarez over 11 years
    @SinanÜnür It's not a requirement, so you can't rely on it, and unfortunately from my testing I can see that webkit saw "may" and ignored anything beyond it. Strangely, IE's got some rather nice large table printing support. Never thought I'd sing its praises on any given point.
  • silbana
    silbana over 11 years
    @lthibodeaux I had assumed the "I see" in the beginning of my message and the bold may made it clear that I realize I can't rely on it. The problem with Safari seems to be not in the page breaking, but rather in the fact that display:table-header-group and display:table-footer-group don't seem to have the effect I consider to be the reasonable and intuitively one.
  • Compaq LE2202x
    Compaq LE2202x almost 10 years
    Do you have sample on how to apply this? I've been trying to assign my table className as splitForPrint but in the JS there's nowhere it took the reference of the element using the className splitForPrint. Only the part where var splitClassName = 'splitForPrint'; but that's it.
  • Chris Bloom
    Chris Bloom almost 10 years
    Here's an easy way to add the divs dynamically with jquery: $(document).ready(function(){$("table tbody th, table tbody td").wrapInner("<div></div>");});
  • Chris Bloom
    Chris Bloom almost 10 years
    Down voted because the script you linked to does not solve the OP's problem without considerable cherry-picking and reconfiguring, and you didn't provide any examples of how one might go about doing it.
  • Aron Lorincz
    Aron Lorincz over 8 years
    I can confirm it works FINE in the latest Chrome and Safari versions.
  • DoctorDestructo
    DoctorDestructo over 8 years
    I can confirm that this does NOT work fine in Chrome or any other Webkit browser (e.g. Safari, Opera)-- unless, by "works fine" you mean "excludes any features that are considered optional". I think what most people want is running headers and footers, and tables that only allow page breaks between rows, neither of which is implemented in Webkit as of 2015/11/13.
  • silbana
    silbana over 8 years
    @DoctorDestructo I think a bug report is in order then.
  • fhugas
    fhugas over 8 years
    Worked like a charm for me, none of the other solutions worked. +1 Had to add a little css to get the correct breaks .page-break { page-break-after: always; }
  • milodky
    milodky about 8 years
    Yep by adding .page-break { page-break-after: always; } it saved my day!
  • Drone
    Drone about 8 years
    @SinanÜnür : I just tried your solution, footer is not working as expected : stackoverflow.com/questions/38027411/…
  • silbana
    silbana almost 8 years
    @MiskateErorr Your statement is false. The HTML shown in your question works fine. You have some other problem. Come up with a minimal case still exhibiting the problem, then update your question.
  • Thomas Kekeisen
    Thomas Kekeisen almost 8 years
    Can confirm that this will make the printing of large tables in chrome 51 a lot more stable.
  • Nurhak Kaya
    Nurhak Kaya almost 8 years
    Thanks to sinan ürün, vicenteherrera and Chrisbloom7. I applied the combination of your answers and it now works!
  • Ryan
    Ryan over 7 years
    Works for me on Chrome and is a nice plain CSS solution.
  • Naila Akbar
    Naila Akbar almost 6 years
    I'm trying same solution, but it does not break table data and disappear extra data instead of displaying it on next page. Any guesses?
  • Stephen R
    Stephen R over 4 years
    You might try setting the @media CSS to tr { display: block; } for Print Only, rather than adding all the extraneous <div> elements. (Haven't tested but worth looking at)
  • Jaspal
    Jaspal about 3 years
    Worked for me as well, a elegant solution to my dynamically filled table solution.
  • Janus Bahs Jacquet
    Janus Bahs Jacquet over 2 years
    It’s impressive – and not least frustrating – that a full 12 years later, this still doesn’t work properly in any browser. Not Firefox, not Chrome, not Safari, not Opera, not Edge (haven’t tested IE). All of them ignore paged media entirely, ignore the (page-)break-* rules or render header and footer rows buggily. Who in the world ever thought it was a good idea to write the CSS 2.1 standard so that these properties don’t have to apply to table rows, quite possibly the place where they’re most crucial? *sigh*
  • silbana
    silbana over 2 years
    @JanusBahsJacquet I just tried it in Firefox, Edge, and Chrome on Windows 10 and all showed the expected print priview and what I expected when printing to a PDF file. That indicates to me the problems you are observing might be caused by the styling of elements in the table cells.
  • Janus Bahs Jacquet
    Janus Bahs Jacquet over 2 years
    @Sinan I asked a question about this a few days ago and just added a snippet that represents the structure I have (also available as a JSFiddle). When I print-preview the result from that, I get a mangled layout in all browsers: the table doesn’t break at all (Firefox), header rows don’t repeat (Safari, Firefox) or overlay body rows (Chromium), table rows are broken mid-line (Chromium, Firefox). Do you not see the same? (I’m on a Mac, but that shouldn’t make a difference.)
  • Janus Bahs Jacquet
    Janus Bahs Jacquet over 2 years
    Or rather… Firefox, which has a ‘Print frame’ function that prints just a specific (i)frame, shows the same print preview as on my standalone page. I cannot find a way to print just the embedded result frame from a JSFiddle in Chromium browsers which don’t have an equivalent function; the Chrome extension entitled Print frame doesn’t seem to work. But I have no reason to expect that the JSFiddle would print any differently from the (identical) standalone version. The table cells contain only plain text, nothing else.
  • Janus Bahs Jacquet
    Janus Bahs Jacquet over 2 years
    @SinanÜnür That looks like most of the CSS isn’t being applied, though – no grid for one thing, and no right alignment in the table cells. Did you do/change something else as well? (I reference using a link ref as well in the actual file.)
  • silbana
    silbana over 2 years
    @JanusBahsJacquet You're right, I had made a single character typo. The problem manifests differently in Chrome and Firefox. I don't have time right now, but I am curious.
  • silbana
    silbana over 2 years
    @JanusBahsJacquet The way Firefox dealt with the table when I applied your styles is key: It put the table on page two and truncated it. It also labeled the table with overflow. So, somehow, your section + body styles are combining to make the table one indivisible block on the grid. Those styles seem to be interfering with the print rules. One can either dive in to CSS grid specs or get into some serious trial & error to figure out how to get the desired display without turning the table into one indivisible block.