I generate html programmatically in order to have it rendered nicely for printing.
I have to print tables that may span several pages. This poses some challenges suc
Another solution to this problem that does not depend on fixed column widths is to wrap each cell's content in a display:block
element and set this to page-break-inside: avoid
. If you don't want to alter the HTML in the first place, you can alter the DOM dynamically on load. As I'm lazy, I'm using jQuery in the following example:
<!DOCTYPE html><html><head><meta charset="utf-8"><style type="text/css">
th, td { border: 1px solid #aaa; }
@media print {
td hack {
display: block;
page-break-inside: avoid;
}
}
</style>
<script src="https://code.jquery.com/jquery-3.5.0.js"></script>
<script>
window.addEventListener('load', function() {
$( "td" ).wrapInner( "<hack></hack>" );
})
</script>
</head>
<body>
<table>
<tr><th>A</th><th>B</th><th>C</th></tr>
<tr><td>more text<br>1<br>2<br>3<br>4<br>5<br></td><td>more text</td><td>more text</td></tr>
<tr><td>1 adasd<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1asd<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>xsdsdfsf</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1<br>2 asda asdas<br>3<br>4<br>5<br>6<br></td><td>xasdada</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4 asdasd <br>5<br>6<br></td><td>x</td><td>x</td></tr>
</table>
</body></html>
The result will look a bit different:
You see the following issues:
But the solution does work with WebKit browsers and still renders as a normal table.
Adding
td, th {
width: 10000px;
}
inside @media print { }
did the trick to make the example code work.
Now the printed columns are properly aligned again, and each row stays on a single page, never spanning two pages.
Works in current versions of Webkit (Safari), FF and Chrome (all tested on macOS only).
Caveat:
Unfortunately, the above is not fool proof. It only works in this example because the cells in each row have the same width.
Once those widths are random, an over-reaching pixel width like 10000px is messing up the columns again.
The only solution I found around this is to provide actual widths that are to be used. Since this is for printing, and since I know that I want to print to a specific paper format (e.g. DIN A4 or US Letter), I can specify the column width precisely with certainty.
So, while this solution is not a good one for a web page view in a browser on-screen, where the total width can vary, it's a good solution for printing, as long as the target print size can be predicted.
Here is the complete html code, setting the column widths to 4cm, 2cm and 3cm:
<!DOCTYPE html><html><head><meta charset="utf-8"><style type="text/css">
th, td { border: 1px solid #aaa; }
@media print {
table, tr, td, th {
page-break-inside: avoid;
}
tr {
display: block;
page-break-before: auto;
}
td:nth-child(1), th:nth-child(1) {
width: 4cm;
}
td:nth-child(2), th:nth-child(2) {
width: 2cm;
}
td:nth-child(3), th:nth-child(3) {
width: 3cm;
}
}
</style></head>
<body>
<table>
<tr><th>A</th><th>B</th><th>C</th></tr>
<tr><td>more text<br>1<br>2<br>3<br>4<br>5<br></td><td>more text</td><td>more text</td></tr>
<tr><td>1 adasd<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1asd<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>xsdsdfsf</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
<tr><td>1<br>2 asda asdas<br>3<br>4<br>5<br>6<br></td><td>xasdada</td><td>x</td></tr>
<tr><td>1<br>2<br>3<br>4 asdasd <br>5<br>6<br></td><td>x</td><td>x</td></tr>
</table>
</body></html>