CSS page-break-after to have even pages in Chrome - css

I am dealing with a task to prepare HTML document for printing in Chrome (requirement), that will contain unspecified number of text elements of unspecified length. The document needs to be printed two-sided, while the elements shall not mix with eachother. So whenever the text spans over odd number of pages, one extra blank page needs to be included.
So far I have read a lot about page-break-before and page-break-after CSS elements, that should do exactly the job I need. However they doesn't seem to work according to the specifications in Chrome. I have noticed it probably quite well-known problem, but haven't found suitable workaround yet.
I created following CSS:
#media print {
.block {
font-family: Arial, Helvetica, sans-serif;
page-break-after: right;
display: block;
float: none;
position: relative;
}
}
When I try it in Edge (44.18362.449.0), it seems to be inserting blank pages just as I need - the test output has 17 pages with page 6 and 12 completely blank. But my Chrome (85.0.4183.121) is not doing the same - here the page-breaks are made, but only one at the time, so the next div starts on even page, which is wrong for my case.
Simple demo code with some lorem-ipsum test data: https://codesandbox.io/s/inspiring-wing-rtwbn?file=/test.css

You definitely should keep in mind, that page-break properties are not supported correctly in most browsers. Check the caniuse report.
Also, here is the question that might help you, it already has some good answers.
Duplicating the main suggestions here with my own commentaries. It may be, that you can use the mix of every of them.
Number 1. (#Nils)
You could maybe try wrapping each of your reports in a div and then using something like jQuery to work out the height of the div to figure out whether it ends on an odd page.
If it ends on an odd page, then inject an empty div with your page-break-after class after that so that it feeds to the next page.
Obviously this will only really work if you know the dpi at which your page prints on your target printer. There's no magic answer that will just work for all scenarios.
72 dpi (web) = 595 X 842 pixels
300 dpi (print) = 2480 X 3508 pixels
("210mm X 297mm # 300 dpi")
600 dpi (print) = 4960 X 7016 pixels
You'd need to experiment a bit here with your standard printer settings to see what works for you/your client(s). If there are multiple scenarios, you could let them select from a drop-down.
So you'd use jquery to check the pixel height of the div, check it against the pixel height of the page to see if the div ends on an odd or even page - then inject the page break if the report ends on an odd page.
You'd also need to know upfront if the user will be using duplex printing - because you'd only need to do this for duplex printing.
Number 2. (#spekary)
Use inline styles for manual page-breaking where it is needed.
<div style="page-break-after: right">
<!-- your content -->
</div>
However, you should keep in mind that this doesn't exactly solve your problem, because, as you said, the document
will contain unspecified number of text elements of unspecified length.
But still, maybe you can play around with this solution.

Related

widows/orphans CSS doesn't not work on Kindle Oasis/Paperwhite

Last 24 hours I spent on figuring out how to control widows/orphans but without using widows and orphans selectors in my CSS. Believe it or not, but Kindle Oasis and Paperwhite for that matter (though I don't have this device at hand) use AZW3 files that do not support either widows:2 or orphans:2 or even break-after:avoid. My text has subheads that, if viewed on Kindle, get left behind at the bottom of the pages. I tried KFX, yes, and it is better in terms of layout (widows/orphans and breaks are supported) but KFX has another problem which is a deal-breaker for me - it underlines every link whether you specify text-decoration:none or not. I have about 2000 links in the text that I don't need underlined. Back to the problem - AZW3 doesn't have support for widows/orphans and page breaks. Can someone suggest how to go about accomplishing this:
p {
widows:2;
orphans:2:
}
or
p {
break-inside:avoid;
}
without the above CSS in order to control where text breaks on Kindle devices.
Thank you.
The only way I found how to force the lines to stay together, i.e. to imitate the break-inside:avoid; behavior, is to put an html element such as img which doesn't break across pages behind my text. Example:
<img src="transparent.png" style="height:3em;width:auto;"/>
<h style="margin-top:-2.5em">this is my header</h>
<p>this is my paragraph</p>
Notice that my PNG is called "transparent" - because that is all it is - a transparent square. My margin-top is slightly less than the height of the image thus still leaving some space above the header. Spacing can be modified with regular margins. Interestingly, this works well on Kindle Fire and Kindle Oasis where <h> and <p> text is forced to go to next page together because of the height of the image. Pending a better implementation of page-break and widow/orphan control on Kindles, this is probably the only way to control this behavior.

Cumulative Layout Shift with Bootstrap 4 grid

I am having a problem with high CLS (Content Layout Shift) while using Bootstrap (4.5) grid for two column layout with column order change.
CLS is a Core Web Vital metric. Basically Google sees a problem when webpage's parts are moving when the page is loading. Supposedly this metric is to affect SEO.
On high resolutions my layout consists of two columns. Main content on the right and sidebar on the left. On lower resolutions sidebar content is pushed down below main content. So HTML looks like this:
<div class="container-fluid">
<div class="row">
<div class="col-lg-8 order-lg-2">
</div>
<div class="col-lg-4 order-lg-1">
</div> 
</div> 
</div>
The problem is that for brief moment while the page renders on desktops, the main content appears on the left side, then milliseconds later it shifts to the right place on the right. With simple pages (with simple DOM or no external resources) the shift is not detectable. 
I've prepared an example of such page. (The source code is on github). To measure CLS I am using Lighthouse in Chrome. In my case when I refresh the page I can see columns moving and Lighthouse informs me of CLS value of 0.326. The result might depend on rendering resources so you might get something different. But it seems Google Page Insight gives similar result:
Anyway, is there a way to avoid such shift while the page renders? 
It seems the problem is more Chrome related then flexbox or bootstrap. It turned out that the problem is caused by premature renderation. Chrome's parser "yields" (so it triggers rendering): 
after reading 65536 bytes of data, 
after encountering <script> tag after reading 50 "tokens" (which I think are basically html tags).
The example I provided shows the first case (but actually my real website experiences CLS because the second one). Both of those cases have "bugs" related to them submitted: 1130290 and 1041006. 
So the answer to the problem is hoping that the "bugs" will get resolved. In the meantime depending on actual cause you can limit file size or remove <script> tags.   
 
Short Answer
Minimise the HTML and the problem seems to go away.
Longer Answer
I did a bit of digging, this isn't a complete "this is exactly what happens" answer but I got enough of an idea to come up with the above solution and to roughly explain my reasoning. I am hoping someone can expand upon the gaps in my knowledge.
So what made me come up with the above solution?
After profiling the page load I notice that there were 2 HTML parse tasks being created.
One dealt with lines 1-770 of the HTML and the other dealt with lines 771 to the end of the document.
Because of this the page appears to render the first 770 lines and then recalculates the layout on the second HTML parse task because you have swapped the order (and the .col-lg-4 column is in the second parsing pass HTML).
You won't see this on a "normal" page as if the page is rendered in DOM order layouts will be correct anyway and the second HTML parsing pass will just add more detail to the layout.
As it appeared to be pretty consistent where it cut the page off I removed all line breaks and white space. My theory being that whatever algorithm is deciding where to split the HTML up is using line number as part of that calculation.
By reducing the effective lines to 15 or so I was hoping to make that algorithm only parse the HTML in one pass.
It actually still does it in 2 but the last pass is the closing </html> tag only so doesn't matter. The result of this is when the parsed HTML is combined with the CSSOM it can calculate the layout correctly.
a bit of a hack but it should work up to certain page depths.
please note - if I doubled the DOM node count this workaround did not work again. If I changed the length of each list item (i.e. put lorem ipsum in) but didn't change the structure it did not make a difference. So it appears to be some combination of number of DOM elements and line number that decides when the HTML parser should stop its first pass.
A possible solution
Go back to old layout models. If you use float:left and float:right it should work. I think this specific issue is a combination of page complexity (number of DOM nodes) and using flexbox.
With flexbox being slightly slower than old layout models and sometimes having to use multiple passes (old layout models are single pass) I would imagine this issue would not persist with the above recommendation.
Where I found out about multiple layout passes in certain scenarios

CSS column bug fix or alternative

Due to Chrome (and other Blink browsers) having a bug where only the first 500 columns are painted i need either a fix/hack, or an alternative solution.
See bug here (there is 509 pages - not 500): https://codepen.io/anon/pen/pLxozK
/* codepen link must be accompanied by code */
column-width: 400px;
I parse EPUB html to a single file. The EPUB's styling must be preserved, so i can't change the html structure.
CSS columns does a good job of rendering such a flat document horizontally. But the 500 limit in Blink means blank pages in Android Webviews.
Is there any workaround for this bug?
Users can adjust font size etc meaning amount of columns can change. So an alternative solution must be able to adjust.
What a cool little bug, I've never seen that before!
By the looks of things you'll need to add display:none to some of your divs. You'll need to use Javascript to see what's in view and see what's not. You'll get the added bonus of not using any system resources unnecessarily as you won't be painting any of the pages that aren't in view.

Preventing Page Breaks in a Table When Printing

I have a page that I'm trying to set up for printing. This page contains a large number of individual tables. The tables are of varying size but, in general, I can fit 2.5 to 3 tables on each page. I'd like to be able to prevent the tables from being broken by a page break. Any idea how I can accomplish that?
I tried this:
.reportTable {
page-break-inside: avoid;
}
Unfortunately, page-break-inside only seems to be supported in Opera (according to W3Schools - I verified that this doesn't work in Firefox 4.0.1).
I can do this to force a page break before after every single table:
.reportTable {
page-break-after: always;
}
This works to insert the page breaks and seems to be supported in all major browsers, but it leaves me with tons of wasted space on the printed documents (roughly half of each page is blank). I really only want a page break if the entire next table won't fit on this page.
I know that I have users utilizing Internet Explorer, Firefox, and Safari so I'd really like to support those as much as possible. Finding something that would also work in Chrome and Opera would be a very nice bonus.
Any ideas?
I've also been looking for an answer to this. The closest I came is to knowing approximately how many lines of output would fit on a page, then calculating how many lines of output the page had. In your case:
1) figure out how many lines of output you can fit on a page.
2) keep track of how many lines you've used already by displaying your first table.
3) calculate how many lines table 2 will take. Add it to table 1's lines and see if you're still below your approximate threshold. If you are, display the table, if not, put a div down with the page-break:always in it to force a new table.
This would give you approximately what you are looking for, but it won't be perfect. every once and a while, you'll have a table that "could" have fit on the previous page, but just didn't quite make the cutoff because you have to be on the low side of estimating how many lines fit on a page.
I haven't however figured out a way to facter in if the content inside a cell or something like that will wrap around into a new line when smushed into a printout page.
Hope that sparks an idea for you.
At present, there seems to be no way to force the browsers that don't support page-break-inside: avoid to do so.
However, since you can fit 2.5 to 3 tables on each page and prefer not to print just a single table using page-break-after: always;, you could opt to insert a special div that forces a page break after every two tables.
So you would include <div class="pageBreak"></div> and hide it for the screen but display it for printing. And you would give it a style of page-break-after: always;. In this way, you get at least two tables per page.
Another suggestion would be to let the user decide whether or not he/she wants to print one table per page or as many as can fit (with some possibly being split over the pages). You can toggle a checkbox to add the page-break-after: always; style to the tables.
to fix this just make
#table{page-break-after:auto;}
This is a very old question, so just wanted to update that page-break-inside: avoid; is now supported in most major browsers. Though there are some quirks to making sure page-break-xxx works (NO parent at any level can have position: fixed, the element and direct parent need to be position: relative and display: block, etc.).
Reference:
https://developer.mozilla.org/en-US/docs/Web/CSS/page-break-inside
https://developer.mozilla.org/en-US/docs/Web/CSS/break-inside
Not all printers are created equally.
You are having problems because the printer is not controlled by either the web browser or the html code. It is controlled by the printer driver that came with the printer. This function (and its settings) belongs to the owner of the computer rendering the page, not to you.
Your code can not know in advance how many lines the printer attached to the user's system can put on a page, or how the printer will lay out a table. It will be different if a user with a different printer opens the page. Just like different screen resolutions, there are different printer pixel resolutions.
So all of the rules that apply to different screens (and their disadvantages) also apply to different printers. Not only can't you know where the printer will break a page, you can't even know how large the printed page is, in terms of how much content fits on a page.
To get all of a table (or multiple tables) onto a page, the user should select the parts he wants to print, and then use Print Selection on the printer dialog box.

FireFox 3 line-height

Firefox 3 has introduced a new behavior in which line-height, when unset, differs from how other browsers render it. Thus, a critical section maybe render too high in that browser. Setting a global percentage doesn't work, since it's basis is different. Setting a unitless value such as "1" doesn't work either. Is there some way to normalize this dimension?
The computed value of line-height: normal varies between platforms, browsers (and different versions of the same browser, as you state), fonts, and even different sizes of the same font (see Eric Meyer's article).
Setting a unitless value such as...
body {line-height: 1.2;}
...should work to normalize the spacing between browsers. If this is not working, can you provide a more-detailed description of your stylesheet?
It's hard (impossible?) to get "pixel-perfect" results, but in order to get results that are as predictable as possible, I try to use a line height that produces a nice round value when multiplied by the font-size. We can't know the user agent's default font size, but 16 pixels is somewhat common.
body
{
font-size: 100%;
line-height: 1.5;
}
If the user agent's starting font size is indeed 16 pixels then the line height of 1.5 comes out to a nice, even 24 pixels. Users can and do change the default font size or the page zoom, though, and different browsers have different methods of scaling the page. Nevertheless, I think I've had reasonable success for a majority of the users. If I can't make the line height come out exactly, then I shoot for a little above the integer rather than a little below, because some browsers seem to truncate values rather than round them.
Also, note that if you use a percentage for the line height, it behaves differently when the value is inherited.
body
{
font-size: 100%;
line-height: 150%;
}
p
{
font-size: 75%;
}
Starting from a base font size of 16 pixels, the line height will be 24 pixels. Within a <p> element the font size becomes 12 pixels, but the line height does not become 18 pixels, rather it remains 24 pixels. This is the difference between line-height: 1.5 and line-height: 150%. When body {line-height: 1.5;} is used, the line height for <p> is 18 pixels.
There is absolutely nothing you can do. Every browser has there way of rendering CSS and content. You can use a "Master" reset (as cowgod suggests), but even then, that's not ultimately going to fix the alignment issues. They are there because of actual rendering engine. Apple the CSS to your existing website and test it. Tell me if it makes pixel perfect across the board. It won't.
The only way to actually achieve pixel perfection is to implement specific CSS for specific browsers. Mozilla has the #-moz-doc, IE has it's own hacks, but none of these are part of the W3C specs, and we all know standards are important. So not much of an option.
As David said above, it's hard. I'm inclined to think impossible actually. And I've spent hours trying, trust me! Almost went mad more times than I care to count. It's a hard pill to swallow, but there is just no way around it, unless everyone used the same browsing engine (which would actually take the internet a great leap forward in my opinion). I mean, it wouldn't be that hard to slap whatever interface you want on your browser, so long as you plugin [gecko][webkit][presto][trident][whatever] to handle the backend... Since the good ones are all open source, you could merge the projects and really get going. People need to learn to play nice together ;)
You CAN solve this:
Set line height to 1, then zero in your text using padding-top and padding-bottom, and set height to auto.
.zeroed_in_element {
padding: 4px 2px 5px 2px;
height: auto;
line-height: 1;
}
You should always "reset" styles to eliminate all browser inconsistencies with element styles.
I like Eric Meyer's CSS Reset. Yahoo has one also.

Resources