I'm struggling to print a dynamic HTML table by using Chrome and Firefox. I'm working on a project using Yii framework and in one of my view I create a HTML table that only fits on multiple pages and should be printed. Height of table rows may vary depending on content.
I'm using THEAD and TBODY elements in my table and I made relevant grouping in my print media CSS. To initiate print dialogue I'm using window.print() JavaScript command .
I read somewhere that Chrome can't divide multiple page long tables properly even if you set page-break-after and page-break-before parameters in your CSS which seems to be true. Firefox can handle theses commands however table header and table content overlap starting from the second page.
Do I need to change my code and draw DIVs instead of table or maybe I should write a JavaScript to split content based on table height?
Please find herewith my CSS for media print:
#page {
margin-top: 1cm;
margin-right: 1cm;
margin-bottom:2cm;
margin-left: 2cm;
size: landscape;
}
.form, h1, .summary, .navbar-inner {display: none;}
table { page-break-after:auto;}
tr { page-break-inside:avoid;}
td { page-break-inside:auto;}
thead { display:table-header-group; }
tbody { display:table-row-group;}
Based on my findings it seems webkit based browsers (e.g.: Chrome) can't handle pagination of long tables even if you set your media print css properly. Furthermore I would say that almost all browsers handles print media style sheet on a different way.
It would be good to see a general solution for this, a standard I mean. I know this is what CSS is for but it doesn't seem to work in this case, or each browser development team interprets it on a different way.
In my case I solved the problem with a JQuery. Someone referred to this JQuery in a different post, but in my case height of some cells are changing dynamically, thus I couldn't use this query, however it led me to a solution.
Just in a nutshell:
I divide my table to a header and data blocks by creating separate tables for those. So, I have a header (a table) and several data blocks (other tables). I print them to the screen one under the other, thus on the screen it seems as a long table.
Then I create an empty table on the page. This is required for the JQuery.
Once everything printed to the screen I run a JQuery which splits my table to pages by looping through all blocks and move each blocks from the original table to my empty table. If the height of X number of blocks reaches the height of the page then it adds a pageberak and a header again and continues looping through on the remaining blocks. At the end my original table becomes empty and my empty table filled up with headers, data blocks and pagebreaks.
My generated HTML page contains the following tables:
<table class='mainheader'>
.
HEADER
.
</table>
<table class='body_block'>
.
DATA
.
</table>
<table class='body_block'>
.
DATA
.
</table>
<table class='body_block'>
.
DATA
.
</table>
.
.
.
<table class='tmp_table'>
</table>
My JQuery:
<script type="text/javascript">
var tableHeight = 0;
var pagebreaker = $('<div style="display: block; page-break-before: always;"></div>');
var header = $('.mainheader');
$('.body_block').each(function()
{
if ((tableHeight + $(this).height()) >= 600){ // I use a 600px height page
$('.tmp_table').append(pagebreaker.clone());
$('.tmp_table').append(header.clone());
tableHeight = 0;
}
tableHeight += $(this).height();
$(this).appendTo('.tmp_table');
});
</script>
I've posted a solution that addresses the problems described in this post, and does not involve trying to predict how many rows will fit on a page (which is impossible since there is no way to know what paper size the user is using). That solution is compatible with all modern browsers, including the webkit-based ones (Chrome, Safari, Opera). For the non-webkit-based browsers (Firefox and Internet Explorer), there's actually a simpler solution: just set page-break-inside: avoid; on the <tr> elements.
Related
I'm creating my first table using HTML and CSS. I used a code generator to create the table "code" (HTML and CSS). I add all of that to a long string and send it to MailApp.sendEmail to include the table in the Email. It works great except that the report lines are too spaced out vertically. I need help reducing the row height or otherwise reducing the vertical spacing. I'd include some of my HTML and CSS but I can't figure out how to put in a format that this freak'n window will accept.
Can someone advise on how to reduce the vertical row spacing in a CSS table?
Try this:
tr { line-height: 5px; }
I am trying to print a large table generated with jQuery in an HTML page. I am using Chrome 26.0.141. The issue is with page break.
i initially used this css
#membersList table { page-break-inside:auto; position:relative}
#membersList tr { page-break-before:avoid; page-break-after:auto;position:relative}
#membersList td{ border:solid 1px #CCCCCC;width:auto;position:relative}
#membersList thead { display:table-header-group;position:relative }
#membersList tfoot { display:table-footer-group;positioion:relative}
this dint worked so i searched and got this link
Google Chrome Printing Page Breaks
based on one of the answer in that link i am using the following CSS attribute
-webkit-region-break-inside: avoid;
But when I run and inspect the element, it is stroked out by default.
What would be the solution? There are lot of posts I searched. They say that recent versions don't support page break. If it's true then what other solution is there to achieve page break in Google Chrome?
Finally I resolved this issue. I made tr{display:block;}
and then I fixed the cell spacing.
Page break only works on block level elements.
As said on MDN:
WebKit browsers doesn't support this property; but some have the
non-standard -webkit-column-break-after and -webkit-region-break-after
with similar parameters as page-break-after.
So you need to use page-break-after with some value which suits you the best. Here are some of them:
The page-break-after CSS property adjusts page breaks after the
current element.
auto:
Initial value. Automatic page breaks (neither forced nor forbidden).
always:
Always force page breaks after the element.
avoid:
Avoid page breaks after the element.
left:
Force page breaks after the element so that the next page is formatted as a left page.
right:
Force page breaks after the element so that the next page is formatted as a right page.
You can also use the break-after property:
The break-after CSS property describes how the page, column or region
break behavior after the generated box. If there is no generated box,
the property is ignored.
You might need to split the table into several parts, and set their page-break-after css property to always. This works (with beta Chrome), I don't know if there is a way to do it in a continuous table.
I have provided a few patches to qt to improve table page breaks. You may wish to check out issue 168 http://code.google.com/p/wkhtmltopdf/issues/detail?id=168#c13
I've used something like several tables to make this thing happen as #sabof mentioned. Say I wanted 11 rows should come on the page.
<table>
11 * <tr></tr>
</table>
<table>
11 * <tr></tr>
</table>
HTML markups;
<div id="printSection">
<div>
</div>
</div>
I created rows dynamically so the JQuery logic were the following;
var j = 23;
for (var i = 0; i < j; i++) {
if (i != 0 && i % 11 == 0) {
$("#printSection div").append("<table><tbody></tbody></table>");
}
var node = "<tr><td>Your Data</td></tr>";
$("#printSection tbody").last().append(node);
}
}
CSS were something like this;
#printSection table {
page-break-after: always;
page-break-inside: avoid;
break-inside: avoid;
}
This works in Chrome (2022):
tr {
page-break-inside: avoid;
}
It will prevent a table row from being split in a page break.
I generally set fixed column widths via CSS with flawless results:
#tableID thead tr th:nth-child(1){width: 75px;}
#tableID thead tr th:nth-child(2){width: 75px;}
/* etc… */
But now I'm in a situation where I won't know the desired column widths until runtime. Here's an excerpt from the code I'm using to dynamically set the column widths:
var tr=$("<tr>");
var colArr=Home.ColDefs[this.statBatchType].colArr;
for(var i=0;i<colArr.length;i++){
var col=colArr[i];
tr.append(
$("<th>")
.html(col.title)
.css("width",col.width)
);
}
this.jqTHead.append(tr);
Sorry this code is a bit out of context but the bottom line is that I'm adding columns, represented by <th> elements, to a table header and setting each one's width.
What ACTUALLY happens, however, is that Firefox is treating the column width as a minimum and then automatically expanding the column width as the user expands his browser window. Consider a case where my JavaScript code sets the width of each column to 75px. Firefox will ensure each column is at least 75px wide, but if the user maximizes (or enlarges) his browser, provided there is sufficient room, each column will be automatically widened.
This is odd to me since the JavaScript code would seem to be the functional equivalent of what I was doing in CSS. Yet the CSS approach doesn't cause this odd behavior.
Any thoughts?
Fix the width of the <table> this will ensure the table does not take the available size and bump the layout.
table-layout: fixed; on the table does exactly this: columns never expand to fit their contents, and if you give the table itself a width, the extra space is divided equally. The contents of cells don't come into play at all.
My table has static width values but sometimes table cells of a certain column can contain text which is too long and which messes up the table's width. I'm looking for a way to dynamically shorten text (kind of like a table grid functionality but then without grids) because it can be of a variable length, and when one hovers over the table cell the entire text is shown without stretching the table.
Currently, I have this hard coded in my script in the following way:
string.substring(0, 65) + '...'; and passing the full text to the 'title' attribute of the table cell.
Note that I don't want to keep using the 'title' attribute. I tried surrounding the text with <span style='position: absolute; background: #EEE'></span> when triggered by the hovering event, but unfortunately that wasn't an appealing solution as the text moved a bit to the bottom while the padding nor the margin style were changed.
The solution can also be a jQuery plugin or JavaScript script.
1. Shortening the original data
I suggest that you consider something more elegant than chopping the string at the 65th character. -- Instead, look for whitespace to break the string at. Only chop mid-word if no whitespace is found.
To save more room in the table cell, use the ellipses character… instead of three periods... Just copy/paste it from this answer. The ellipses character could also be styled with a different or smaller font.
2. Showing the original data on hover
I prefer YUI. Their tooltip widget works well for this. An example.
You should try this CSS instruction:
td { break-word: word-wrap; }
that works in many browsers (yes, including IE 6, even IE 5.5 but not Fx 3.0. It's only recognized by Fx3.5+. Also good for Saf, Chr and Op but I don't know the exact version for these ones) and don't do any harm in the other ones.
If table's width is still messed up, there is also:
table { table-layout: fixed; }
th, td { width: some_value; }
that will force the browser to use the other table algorithm, the one where it doesn't try to adapt many situations including awkward ones but stick to what the stylesheet says.
I have a html table and I want to freeze the header row th tag for scrolling the data. How I can do that? Does I need to use the Dom?
Thanks !!
My solution is to use two tables and fix the column widths. The lower table is in a scrollable div and has no header.
If you take Accessibility seriously, two tables is not the way to go since it breaks rules.
There are ways to do it in pure CSS, but it is a headache to get it to work in all browsers. There are a few examples out on the net, but they do not all work 100% with IE without tweaks.
I am currently working on a CSS only version, this is getting pretty close: http://www.coderanch.com/t/431995/HTML-JavaScript/Table-with-fixed-header-scolling#1918825
Does not work in IE8rc1 yet, IE6/7 has a border issue and you have to live with the scrollbar looking different in FF vs IE.
With FireFox, you can put style="height: 200px; overflow-y: auto" But to have a pure CSS version compatible with all major browsers, I've use this example since IE doesn't support syles in tbody or thead.
I have come up with a solution that sort of combines two previously mentioned ones. It uses jQuery and two tables , one for the header and one for the content. The header table is set to a width of 100% with no column widths set. At the bottom of the content table there is a row defined to match the header table with the column widths set. This row is hidden so that it is not shown, but retains the column widths.
For this example I gave my header row an ID of 'Header1' and the bottom row and ID of 'Header2'. Also I wrapped the content table inside a div with an ID of 'scrollTable'.
I set styles in my CSS file for the scrollTable ID, see below:
#scrollTable {
height:250px;
overflow-x:hidden;
overflow-y:scroll;
}
Now for the jQuery part. Basically what I'm doing here is taking the widths of the bottom row columns and setting the header columns to match. I stretch the width of the last column of the header so that it fits over the top of the scroll bar. See code below:
$(document).ready(function(){
var maxWidth = $('#Header1').width(); // Get max row Width
$('#Header2 th').each(function(i) { // Set col headers widths to to match col widths
var width = $(this).width();
$('#Header1 th').eq(i).width(width);
});
var blankSpace = maxWidth - $('#Header1').width(); // Calculate extra space
$('#Header1 th:last').width( $('#Header1 th:last').width() + blankSpace ); // Stretch last header column to fill remaining space
});
I have tested this successfully on IE 6, 7 & 8, Firefox 3.0.1.4, Chrome 3.0.195.25, Opera 10, and Safari 3.2.2 on Windows XP.
I've done it in the past using CSS by defining a height for the <TBODY> tag on my table, and using overflow:auto. This was a while ago, and I think there were some compatability problems. I don't remember precisely what they were, but this solution may work for your problem.
the best solution (the one that scales with lots of data) is to use 2 tables like aaron said, the top table has the headers, and the bottom table should have the headers as the last row (or the footer), but with opacity of 0, so that you cannot see them.
This the headers at the bottom make the bottom table have the same column widths as the top table, making things line up. make sure you style both header and footer the same.
you will also have to create a seperate scroll bar for vertical scrolling to the right of the table, because otherwise the scroll bar will mess up your widths. add a scroll event listener to set the scrolltop of the table to the scrolltop of the scrollbar, and resize the scroll bar to be the same height as the table.
its pretty easy, actually =)
Create a single table as you normally would to meet accessibility concerns. Dynamically create a new table based on the thead using jQuery (copy the thead) and inject it into the page above the first table and give it the fixed position. It should stay in place while the rest of the table scrolls, but it will still remain accessible and work with JavaScript disabled.
Have you tried this plugin from JQuery ? http://plugins.jquery.com/project/floatobject
I believe this does what you want. Check out the demo # http://amirharel.com/labs/fo/float_demo.html
Cheers!