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.
Related
I want to create a responsive, mobile optimized reading experience similar to an epub/ebook reader, like the Kindle app, or iBooks, using dynamic html as the source.
Imagine a long article or blog post that requires a lot of vertical scrolling to read, especially on a small mobile device. What I would like to do is break the long page into multiple full-screen sections, allowing the user to use left/right navigation arrows and/or the swipe gesture to "page" through the article.
There are many JS libraries available that can create a "slide show" or "carrousel" of pre-defined slides (using divs or other container elements). But I want the text and html content to dynamically re-flow to fit any device viewport and still be readable... just like an epub/ebook user interface, like the Kindle app or iBooks. So, for the same article, there would be many more "pages" on a phone than there would be on a tablet or desktop viewport, and those "pages" would need to be dynamically created/adjusted if/when the viewport size changes (like switching from portrait to landscape on a mobile device).
Here is an example of a javascript .epub reader: epub.js
... notice the responsive behavior. When you resize your viewport, all the text re-flows to fit the available space, increasing or decreasing the total number of "pages". The problem is that epub.js requires an .epub file as its source.
What I want is the same user interface and functionality for an html page.
I have searched and searched for some kind of library that can do this out of the box, but haven't been able to find anything.
I realize that I could use a conversion script to convert my html page into an .epub file, and then use epub.js to render that file within the browser, but that seems very round-about and clunky. It would be so much better to mimic or simulate the .epub reader user experience with html as the direct source, rendering/mimicking a client side responsive ebook user experience.
Does anyone know if something like this already exists, or how I could go about building it myself?
The crucial functionality is the dynamic/responsive text-reflow. When the viewport dimensions are reduced, the text/content needs to reflow to the next "page" to avoid any need for vertical scrolling. I don't know how to do this efficiently. If I were to code it myself, I might use something like the jQuery Columnize plugin, setting all columns to width: 100vw; height: 100vh, so that each column is like a "page", and then figuring out how to create a swipe UI between those "pages".
Any help is much appreciated!
This becomes very difficult if the html page is complex, eg with precisely positioned elements or images. However if (as in the epub.js example) the content consists only of headings and paragraphs, it is achievable.
The basic idea is to progressively add content until just before the page overflows. By keeping track of where we start and stop adding content, clicking to the next page is a case of changing the page start to the previous page end (or vice versa if you're going back).
Process for reshaping content into pages
Let's assume you have all your content in one long string. Begin by splitting all the content into an array of words and tags. It's not as easy as splitting by whitespace as whitespace between < and > should be ignored (you want to keep classnames etc within each tag). Also tags should be separated as well, even if there is no whitespace between the tag and a word.
Next you need a function that checks if an element's contents overflow the element. This question has a copy-paste solution.
You need two variables, pageStart and pageEnd, to keep track of what indexes in the array are the beginning and end of the current page.
Beginning at the index in pageStart you add elements from the array as content to the page, checking after each add whether or not the contents overflow. When they do overflow you take the index you're up to, minus 1, as the index for pageEnd.
Keeping tags across page breaks
Now if all's ticketyboo then this should fill the page pretty well. When you want to go to the next page set your new pageStart as pageEnd + 1 and repeat the process. However there are some issues that you may want to fix.
Firstly, what happens if the page overflows in the middle of a paragraph? Strictly speaking the closing tag, </p>, is not required in HTML, so we don't need to worry about it. But what about the start of the next page? It will be missing an opening tag and that is a major problem. So we have make sure we check if the page's content begins with a tag, and if it doesn't then we get the closest opening tag prior to the current pageStart (just step back along the array from pageStart) and add it in before the rest of the content.
Secondly, as shown in the example, if a paragraph continues onto the next page, the last line of the current page is still justified. You need to check if pageEnd is in the middle of a paragraph and if so add syle="text-align-last:justify;" to the opening tag of that paragraph.
Example implementation
A pen showing all this in action is at https://codepen.io/anon/pen/ZMJMZZ
The HTML page contains all content in one long element. The content is taken directly from the container #page and reformed into pages, depending on the size of #page. I have't implemented justifying the last line if a page break occurs within a paragraph. Resize the #page element in the css and see how the content resizes itself - note that since the page size is fixed you'll have to use click forward and back to trigger a recalculation. Once you bind the page size to the window size, recalculating pages on the fly simply involves adding a resize event listener to the window that calls fillPage.
No doubt there are numerous bugs, indeed it will sometimes display things incorrectly (eg skipping or repeating words at the beginning or end of a page), but this should give you an idea of where to start.
Take a look at this repository on GitHub. Otherwise, you can create a one-page website with many sections, each one as high as the viewport, by using only CSS (demo):
.section { height: 100vh; }
or by using JavaScript, adding an anchor to each section to navigate between them, and applying a responsive unit (my demo) for the text of each section, to adapt it on resize... Something like this:
var curr_el_index = 0;
var els_length = $(".container").length;
$(".next_section").on("click", function(e) {
curr_el_index++;
if (curr_el_index >= els_length) {
curr_el_index = 0;
}
$("html, body").animate({
scrollTop: $(".container").eq(curr_el_index).offset().top
}, 300);
return false;
});
$(".previous_section").on("click", function(e) {
curr_el_index--;
if (curr_el_index < 0) {
curr_el_index = els_length - 1;
}
$("html, body").animate({
scrollTop: $(".container").eq(curr_el_index).offset().top
}, 300);
return false;
});
* {
border: 0;
margin: 0;
padding: 0;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
body {
background-color: #1a1a1a;
}
section {
height: 100vh;
background-color: #eee;
border: 2px solid red;
font-size: 6vw;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="container">Section 1 Previous Next</section>
<section class="container">Section 2 Previous Next</section>
<section class="container">Section 3 Previous Next</section>
<section class="container">Section 4 Previous Next</section>
<section class="container">Section 5 Previous Next</section>
EDIT #1
An idea of algorithm, that come from a my codepen, that uses the same jQuery plugin:
Create your reader layout, copying the whole text in it
Use this jQuery plugin to check the text inside the viewport (demo)
Count the number of characters/WORDS with "Onscreen" label in the
viewport (a references)
Split the whole text in a list containing as many characters/WORDS as
there are in the "Onscreen" label
Create a section for each element of the obtained list, filling each
section with the relative text; the number of elements of the list
gives you the number of pages (sections) of the whole text. You may
navigate between sections like above
On resize event, redo [2-5] algorithm steps
Cheers
The idea is to have a div that will contain the whole text (let's call this div #epub_container). Then, you will have a div with the same size of the page viewport (let's call it #displayer) and it will contain #epub_container.
#displayer will have css overflow:hidden. So when the site loads, it will only show the first page, because the rest of the #epub_container will be hidden.
Then you need a page navigator to increment/decrement the page number. When the page number changes, we will move the top offset of the #epub_container based on that.
This is the jQuery function:
function move_to_page() {
var height = window.innerHeight;
var width = window.innerWidth;
var $displayer = $('#displayer');
var offset = $displayer.offset();
$displayer.height(height - offset.top - 5);
var $epub = $('#epub_container');
var offset_top = offset.top - $displayer.height() * m_page;
$epub.offset({top: offset_top, left: offset.left});
}
JSFiddle
EDIT: call move_to_page() after the text reflow in order to recompute the pages.
I created a plugin that handles this perfectly. It has features like dark mode, font changing, line height adjustment, select chapter in a side nav menu, save and restore scrolling/reading position. You can find it for free on git hub at https://github.com/E-TechDev/Html-Book-Reader
Screenshots
Light Mode Dark Mode Side Nav Menu Change Font Adjust Paragraph
You can try CSS scroll snap points on text with columns
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap_Points
Somehow make the columns as wide as the viewport, and allow horizontal snapped scrolling.
Update
I mean to try to do the text flowing entirely using css. Pen:
https://codepen.io/ericc3141/pen/RYZEpr
body {
scroll-snap-type: mandatory;
scroll-snap-points-x: repeat(100%);
}
#columns-test {
height: 80vh;
columns: 90vw auto;
}
All you need is to insert a page break at the right places when you load the page. You can take the cue from here:
Dynamic Page-Break - Jquery
Here you can set the page height to your viewport height. You can handle the rest with javascript and css.
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.
I have a table containing data which I do not want to wrap onto more than one line, so this is the CSS applied to the cells:
td {
white-space: nowrap;
overflow: hidden;
}
This works fine and dandy, however, I'd like to show the users a tooltip containing the full content of that cell, but only if some overflowing text is being hidden. Therefore, I need a programmatic way to tell if the cropping/truncation is occurring.
In Safari and Chrome, I can inspect the element.scrollWidth property, and if it is larger than element.clientWidth then it is being cropped. However, no matter how much text is in the cells, Firefox always reports these two to be the same (give or take a couple of pixels for the border/padding/margin).
I've put an example together on JSBin so you can see for yourself. Try resizing your window and look at the output.
http://jsbin.com/equbo3/4
ps: For me, the solution doesn't need to work in IE, but if you know of a way for it too, please do share.
(function(t) {
var c, h, i;
for (i = 0; i < t.length; i++) {
c = t[i];
h = c.clientHeight;
c.style.whiteSpace = 'normal';
if ( c.clientHeight > h ) { /* add tooltip */ }
c.style.whiteSpace = 'nowrap';
}
})( ARRAY_OF_CELLS );
Just pass in the array of TD elements into the above function, and define custom behavior for the cells that overflow inside the { /* add tooltip */ } block.
Live demo: http://jsfiddle.net/nJarj/1/
In the live demo, you can see that the cells that overflow have a red color.
The problem seems to be with how FF interprets table cells.
If you change the overflow value to 'auto' or 'scroll' it displays as if it were 'overflow:visible' which won't return an appropriate scrollWidth. This doesn't happen in Chrome.
If you change the display type to 'display:block' you get the correct scroll bar and scroll width returned, but obviously you lose the tabular layout.
Potentially you could wrap the contents of the cells in another tag with the following styles:
newTag {
display:block; /*just in case it is not default*/
overflow:scroll;
}
as I have here.
This could be done in the markup or dynamically as you do your calculations.
It is not a great solution I know - but I don't know of any display settings to get around this (cycled through options using firebug).
Hope this helps in some way
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!