Page break only between tbody when printing from Chrome - html

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

Related

Printing a table over multiple pages

I am doing a project for my employer, and trying to print a large data table over multiple pages for printing purposes.
When I am trying to print the table however, the top borders seem to overlap onto the previous page.
Image preview:
I have tried editing the borders to be different thicknesses, and applying the CSS properties to now allow a to be split over multiple pages, however none of it has had any effect.
Right now I have removed all CSS from the page apart from Bootstrap and the page break rules, but am still having the same issue
My code:
table {
page-break-inside: auto
}
tr {
page-break-inside: avoid;
page-break-after: auto
}
thead {
display: table-header-group
}
tfoot {
display: table-footer-group
}
<table id="test" class="table table-bordered thead-light">
<thead>
<tr>
<th scope="col">Date / Time</th>
<th scope="col">Log Class</th>
<th scope="col">Reason</th>
<th scope="col">Detail</th>
<th scope="col">Hold State</th>
<th scope="col">UL ID</th>
<th scope="col">SKU</th>
<th scope="col">Location</th>
<th scope="col">Destination</th>
<th scope="col">Qty</th>
<th scope="col">User</th>
</tr>
</thead>
<tbody>
Table Data
</tbody>
</table>
I would have expected the borders to remain on the page which the starts, and not clip onto the previous page, however as you can see in the original image, it is still clipping.
Any help would really be appreciated.
I cant understand your real issue but i think you are trying to give different border to th, td then add different class to required one and add border css.
Example:
.border-style {
border:2px solid red !important;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Bordered Table</h2>
<p>The .table-bordered class adds borders to a table:</p>
<table class="table table-bordered">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr>
<td>John</td>
<td >Doe</td>
<td>john#example.com</td>
</tr>
<tr>
<td>Mary</td>
<td class="border-style">Moe</td>
<td>mary#example.com</td>
</tr>
<tr>
<td>July</td>
<td>Dooley</td>
<td>july#example.com</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
I got your issue but not sure why try to inspect that and do a css display:none; if anything on that border
Cant find the issue because i cant inspect on that
Sorry
And check if anywhere you add a display:inline-block i have a issue with this recently
I had this exact problem and unfortunately I didn't find a proper solution - but read on!
The issue seemed to be that the top border from the table header 'leaked' over to the previous page. After some trial an error I found two workarounds (short of deleting the project entirely).
"Solution" #1 - Remove stylings :'(
Removing all borders AND BACKGROUNDS on the top row (including the table border) meant that the leaking pixels are invisible. Hurrah!
#media print {
table, thead tr, thead th {
/* You might not need '!important' with your styling, but
I found with bootstrap that this is the safest option. */
background: none !important;
border: none !important;
}
}
<table class="table table-bordered">
<thead>
<tr>
<th>Awww...</th>
<th>These</th>
<th>are</th>
<th>boring</th>
<th>headers!</th>
</tr>
</thead>
</table>
But while this fixed my issue, it broke my heart. This wasn't the solution I needed...
"Solution" #2 - Hack at it 'till it breaks!
After some considerable crying, I found that I could add another dummy row above my headers and remove the styling on that instead!
"What a terrible solution - thanks Mark!"
th {
border: solid 1px hotpink;
}
#media not print {
.print-only {
display: none;
}
}
<table class="table table-bordered">
<thead>
<!-- This is where the magic is. This row 'pads' the table
headers and keeps them on the same page -->
<tr class="print-only">
<th style="border: none !important; background: none !important;"></th>
</tr>
<tr>
<th>Look</th>
<th>at</th>
<th>these</th>
<th>stylish</th>
<th>headers!</th>
</tr>
</thead>
</table>
So yeah... when one of you coding geniuses (genii?) come across this answer and realize that the rest of us are down shit's creek, please feel free to post a real solution to this headache :)

Group multiple consecutive row cells into one with CSS?

Ok, here's a graphic to explain what I'm talking about:
The first table would be what my html currently produces and the second table is what I'd like it to produce.
#animalTable{
display: table;
}
.animalRow{
display: table-row;
}
.animalCell{
display: table-cell;
width: 33%;
}
<div id="animalTable">
<div class="animalRow">
<div class="animalCell">Dog</div>
<div class="animalCell">Milton</div>
<div class="animalCell">1/2/1998</div>
</div>
...
</div>
What would be the best/easiest way to get my desired table? I know I could brute force it by creating sub-tables inside the main table but I was wondering if there was a better way?
Also, sorry if this is a dumb question.
I suggest using tables instead of div for this specific case. Here is why you should Use tables for what they are meant to and div's for what they are meant to.
What you are looking for is called Colspan and Rowspan, both are HTML td and th attributes.
Example:
<table>
<tr>
<th>Month</th>
<th>Savings</th>
<th>Savings for holiday!</th>
</tr>
<tr>
<td>January</td>
<td>$100</td>
<td rowspan="2">$50</td>
</tr>
<tr>
<td>February</td>
<td>$80</td>
</tr>
</table>
You can read further on w3schools.
Hope this helps.
Simple, add different class or id selectors and in the css, remove all borders and re-add the ones you want to keep. Example,
div{
border: none;
border-top: solid 1px black;
border-left: solid 1px black;
}
Correct me if I am misunderstanding. Otherwise, if you have any questions don't hesitate to ask!

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.

Chrome 1px unavoidable Spacing between td

I'm having a problem that appears to only occur in Chrome and nowhere else. I have a table, which has a style applied to it on hover. In other browsers, the style is applied when hovering over any part of the row. However, in chrome, at the edge of each td, the style is no longer applied. If I "inspect element" on this small 1px wide area between cells, the elements pane shows that Chrome thinks I am within the table, but not within the row itself. Here is some code which produces this effect:
CSS:
table.tablesorter tbody tr:hover {
background: #8dbdd8;
cursor: pointer;
}
table {
border-collapse: collapse;
border-spacing: 0px;
border: none;
}
HTML:
<table id="myTable" class="tablesorter">
<thead>
<tr>
<th>Title1</th>
<th>Title2</th>
<th>Title3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bach</td>
<td>42526</td>
<td>Dec 10, 2002 5:14 AM</td>
</tr>
<tr>
<td>Doe</td>
<td>243155</td>
<td>Jan 18, 2007 9:12 AM</td>
</tr>
<tr>
<td>Conway</td>
<td>35263</td>
<td>Jan 18, 2001 9:12 AM</td>
</tr>
</tbody>
</table>
Anybody seen this before / know a way around it?
If it helps, I am using Chrome 13.0.782.220.
Live demo: http://jsfiddle.net/yNPtU/
Interestingly this is not caused by the border. If you set a border width to 10px, there is still only 1px in-between the cells that causes this.
I tried setting the position of the tds which seemed to work. Here is a demo: http://jsfiddle.net/lnrb0b/6harr/
Note: I've added the padding in to keep the size consistent
As mentioned in this question, this will solve it:
td {
padding: 2px 5px;
position:relative;
}
And the JsFiddle.
The table has cellpadding and cellspacing by default. You will need to add:
<table cellspacing="0" cellpadding="0">
Give border-spacing:-1px in css.

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

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.