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

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.

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

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>

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.

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.

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

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!

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.

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.

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.

I have a face like this problem. You can solve this problem using CSS properties.
#media print {
table{page-break-after: auto;}
}
Note:
You can not use this property with empty or on absolutely positioned elements.

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

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.

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.

Related

Page break only between tbody when printing from Chrome

I have a <table> of data where consecutive rows are conceptually related and need to stay together. I've group each pair of rows in a <tbody> tag. When it comes time to print the table, I want to make sure that page breaks only happen between <tbody> tags.
I've tried some variations of page-break-inside: avoid and page-break-after: auto, but can't seem to get it to work in Chrome 42 (see screenshot below)
However, it does seems to work as expected in Firefox 40 and IE 11 though. It looks like page-break-* might only apply to block level elements. Is there a good way to accomplish this in html/css?
Example code:
<!doctype html>
<html>
<head>
<style>
table {
width: 70%;
border-collapse: collapse;
}
thead {
display: table-header-group;
text-align: left;
border-bottom: 2px solid #000;
}
tbody {
page-break-inside: avoid;
border-bottom: 1px solid #ccc;
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<th>Project #</th>
<th>Owner</th>
<th>% Complete</th>
</tr>
</thead>
<tbody>
<tr>
<td>HR-123</td>
<td>Arther Dent</td>
<td>42%</td>
</tr>
<tr>
<td colspan='3'>Description: Find travel guide to get me back to earth.</td>
</tr>
</tbody>
<tbody>
<tr>
<td>RD-123</td>
<td>Frodo Baggins</td>
<td>9%</td>
</tr>
<tr>
<td colspan='3'>Description: Find a better way to get the ring to Mordor.</td>
</tr>
</tbody>
<!-- repeat tbody sections as necessary to get onto the second page -->
</table>
</body>
</html>
Here's a JSFiddle that'll give you a bit of an idea of what I'm trying to accomplish.
Edit: I considering not using a table but didn't since (i) I want my columns to line up, and (ii) I really don't want to hard-code column widths to make sure they're all the same.
Try wrapping it all in a
make that specific a block element (http://learnlayout.com/inline-block.html)
then use page-break-*

Internet Explorer CSS for cell with div inside

When I put a div inside a cell, the border of the cell is not properly shown in IExplorer: it is thinner for the cell that has a div inside.
Here's an example:
<html>
<head>
<style>
table { border-collapse: collapse; }
table, td, th { border: 2px solid black; }
</style>
</head>
<body>
<table>
<tr>
<th>Firstname</th>
<th>Lastname</th>
</tr>
<tr>
<th><div style="float:left;width:100%;height:100%;background-color:blue;">Peter</div></th>
<th>Griffin</th>
</tr>
<tr>
<th>Lois</th>
<th>Griffin</th>
</tr>
</table>
</body>
</html>
I've tried doing a "relative" positioning for the div and doing a "cellspacing=0" for the table and none of them work. The cell borders are properly shown in Chrome and Safari, but I don't know why IExplorer keeps doing making some of the borders around the filled cell thinner.
I've found a lot of closely related topics, but none covered this (or I didn't know how to apply it to this particular case). So I come to you in desperation.
Do you know any way to solve it?
Thanks in advance.
PS: I'm talking about IExplorer 11, I don't know what happens in earlier versions.

W3C Validator tells me I have an Error, not sure how to fix

So I am writing a css page for my class, and I noticed that the style which I applied to span is not applying at all, so I went to http://validator.w3.org/ to check what I did wrong and it gave me this error message
"Line 32, Column 6: Start tag span seen in table."
This is my line 32
<span><tr><td>Mars needs moms</td><td>$150,000,000</td><td>$38,992,758</td><td>$130,503,621</td><td>2011</td></tr></span>
Here is the code for that particular style
span{background-color=:#666;font-weight:bold;color:white;}
Basically my goal is to make this table haveevery other row in the table with a background color being black with the text being white
This is the full code, incase the error made which isn't applying this style is somewhere else. there are other styles in there which don't apply to anything yet, as this is not finished yet
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Lowest Grossing Movies of all time</title>
<style>
span{background-color=:#666;font-weight:bold;color:white;}
p{text-decoration:underline;line-height:200%;}
h1{text-align:center;font-size:125%;}
table{border-collapse:collapse;}
th,td{padding:25px;}
</style>
</head>
<body>
<h1> Lowest Grossing Movies of All Time </h1>
<table border="1">
<tr><th>Title</th><th>Production Budget</th><th>World Wide Gross</th><th>Net Loss</th> <th>Release Year</th></tr>
<span><tr><td>Mars needs moms</td><td>$150,000,000</td><td>$38,992,758</td> <td>$130,503,621</td><td>2011</td></tr></span>
<tr><td>The 13th Warrior</td><td>$160,000,000</td><td>$61,698,899</td><td>$129,150,551</td><td>1999</td></tr>
<span><tr><td>The Lone Ranger</td><td>$225,000,000</td><td>$243,377,083</td><td>$103,311,459</td><td>2013</td></tr></span>
<tr><td>R.I.P.D.</td><td>$130,000,000</td><td>$66,627,120</td><td>$96,6865,440</td><td>2013</tr>
<span><tr><td>John Carter</td><td>$250,00,00</td><td>$282,778,100</td><td>$108,610,950</td><td>2012</td></tr></span>
</table>
</body>
</html>
The biggest problem you're facing is that there are limited elements that are valid children of the HTML table element, these are:
colgroup,
caption,
thead,
tfoot,
tbody, and
tr
So removing the span elements from the table solves that problem. Also, you'd forgotten to close one of the td elements (you closed the tr, but forgot the td); this is why readable HTML is easier to maintain (it's simply easier to see the code, and omissions, when it's indented and white-spaced).
Incidentally, using your original HTML, had you used your browser's developer tools (such as Web Inspector under Chromium, or Firebug under Mozilla), you'd have been able to inspect the DOM, which would've shown you the brower's (unpredictable and unreliable) reordering of the HTML in order to produce a valid document). For example, Web Inspector shows:
JS Fiddle 'source' for above image.
Note the three span elements moved before the table element, from the table itself.
Your corrected HTML:
<h1> Lowest Grossing Movies of All Time </h1>
<table>
<tr>
<th>Title</th>
<th>Production Budget</th>
<th>World Wide Gross</th>
<th>Net Loss</th>
<th>Release Year</th>
</tr>
<tr>
<td>Mars needs moms</td>
<td>$150,000,000</td>
<td>$38,992,758</td>
<td>$130,503,621</td>
<td>2011</td>
</tr>
<tr>
<td>The 13th Warrior</td>
<td>$160,000,000</td>
<td>$61,698,899</td>
<td>$129,150,551</td>
<td>1999</td>
</tr>
<tr>
<td>The Lone Ranger</td>
<td>$225,000,000</td>
<td>$243,377,083</td>
<td>$103,311,459</td>
<td>2013</td>
</tr>
<tr>
<td>R.I.P.D.</td>
<td>$130,000,000</td>
<td>$66,627,120</td>
<td>$96,6865,440</td>
<td>2013</td> <!-- you omitted a closing </td> tag here -->
</tr>
<tr>
<td>John Carter</td>
<td>$250,00,00</td>
<td>$282,778,100</td>
<td>$108,610,950</td>
<td>2012</td>
</tr>
</table>
Using CSS:
table {
border-collapse: collapse;
}
th,
td {
border: 1px solid #000;
}
/* using ':nth-child(odd)' to style the 'td' elements
of the alternate/odd rows of the table */
tbody tr:nth-child(odd) td {
background-color: #ffa;
}
JS Fiddle demo.
References:
<table>.
:nth-child().
In most modern browsers this could be achieved with css:
tr:nth-child(even) {
background-color:#666;
font-weight:bold;
color:white;
}
No span tags required. (Remove them)
JS Fiddle: http://jsfiddle.net/uB2GR/
You've placed <span> elements between two <tr> elements. This is not valid HTML. You need to place your entire <span> inside a table cell.
<tr><td><span>Some stuff</span></td><td><span>More stuff</span></td></tr>
if you're doing this for styling purposes there's probably a better way with classes applied to the <td> elements

Colspan doesn't work with <td> width set? (IE7)

I can't get colspan to work when I use a fixed width (IE 7)? Why?!
Sample Code:
<html>
<head>
<style>
.inputGroup td
{ width:250px; }
</style>
</head>
<body>
<table class="inputGroup">
<tr>
<td>cell1</td>
<td>cell2</td>
</tr>
<tr>
<td colspan="2">This should span two columns but it doesnt</td>
</tr>
<tr>
<td>cell1</td>
<td>cell2</td>
</tr>
</table>
</body>
</html>
Help anybody? :(
it does, but you've limited the width. If you want, try creating another class called '.doubleSpanInputGroup' or something with width 500 and set that class onto the spanning column.
eg.
<html>
<head>
<style>
.inputGroup td
{ width:250px; }
.inputGroup td.doubleInputGroup
{ width:500px; }
</style>
</head>
<body>
<table class="inputGroup">
<tr>
<td>cell1</td>
<td>cell2</td>
</tr>
<tr>
<td colspan="2" class="doubleInputGroup">This should span two columns but it doesnt</td>
</tr>
<tr>
<td>cell1</td>
<td>cell2</td>
</tr>
</table>
</body>
</html>
EDIT: made the new style more hierarchical
Try making the rule apply to tr instead of td and make the width 500px instead, as such:
.inputGroup tr { width: 500px; }
The problem you're having is because you've set a limit on the td to be at most 250px wide, so the browser is simply following your instructions.
in general manner :
table tr:first-child td:first-child{ width:86px; }
if this is the only width all first column take this width and colspan in ie7 will work
I tried to set the width of the colspan cells to auto, seemed to work fine in IE7/8/9
.yourColSpanTD { width: auto !important; }

CSS Line-Through not being removed

I've got some code that puts a line-through on a TR for deleted rows, but this means that my "Actions" column (that only has) buttons suffers. This is because there are individual spaces between the buttons, which wind up getting line-throughed as well.
After poking around on W3Schools, it boggles me why this example doesn't work:
<html>
<head>
<style type="text/css">
tr {text-decoration:line-through}
</style>
</head>
<body>
<table>
<tr>
<td>this needs to be line-throughed</td>
<td style="text-decoration: none !important;">This shouldn't be line-throughed.</td>
</tr>
</table>
</body>
</html>
How am I supposed to clear the line-through on child elements?
EDIT
I've updated my example - the problem is that I do not want to take the style off the parent element, just a single child element.
You shouldn't have to use important or inline styles for this. Try
h2 {text-decoration:line-through;}
h2 span {text-decoration: none; border: 1px solid black;}
EDIT
In that case with tr since yeah you applied text-decoration to it, you have to take text-decoration off the same element tr not td. Otherwise do:
tr td { text-decoration: whatever }
and then when needed
<td style="text-decoration: none;"></td>
There was a similar question a little while back and according to that answer you can't do what you're trying to accomplish.
EDIT: Given your example, why not just apply the line-through to TD elements individually
<html>
<head>
<style type="text/css">
td.deleted {text-decoration:line-through}
</style>
</head>
<body>
<table>
<tr>
<td class="deleted">this needs to be line-throughed</td>
<td>This shouldn't be line-throughed.</td>
</tr>
</table>
</body>
</html>
The line-through is applied to the H2, so you have to take it off of the H2.
<html>
<head>
<style type="text/css">
h2 {text-decoration:line-through}
h2.alt { text-decoration: none; }
h2.alt span { border: 1px solid black; }
</style>
</head>
<body>
<h2>Line-through</h2>
<h2 class="alt"><span>This is heading 2, and shouldn't be line-throughed.</span></h2>
</body>
</html>
(Viewable here: http://jsbin.com/anopa/)
The child (span) cannot affect the style of the parent (h2), which is where the style is applied. You have to alter where the style was originally applied.
Edit: updated example
One way to fix this would be to change
tr {text-decoration:line-through}
to
tr td {text-decoration:line-through}
As a result, the line-through is on the individual table cell and not the whole row. This allows you to specify a different style on a single cell.
BTW, the issue doesn't seem to exist with the example code you've given on IE5.5+. In FF3.5, however, the example behaves as you've explained. I'm not sure which is the actual correct behavior.
Try This
<html>
<head>
<style type="text/css">
tr td {text-decoration:line-through;}
tr td.noline { text-decoration:none;}
</style>
</head>
<body>
<table>
<tr>
<td>this needs to be line-throughed</td>
<td class="noline">This shouldn't be line-throughed.</td>
</tr>
</table>
</body>
</html>
Notice that the style is "tr td" for both.
<td style="text-decoration: none>
It works, unless what you're trying to uncross is a link to a URL.
Then this phrase also defeats the link.