Orphan CSS: How avoid headers (h1, h2...) on bottom page? - html

I have a large HTML document with headers (h1, h2, h3...) and paragraphs. When I print the document, I want that, automatically, headers at bottom of document go to next page:
How can I do? I use "orphans: 3" CSS with paragraphs and works with "p" tags, but with h1 or h2 don't work.
#page {
size: A4;
}
p {
orphans:3;
}
h1, h2 {
orphans:3
}
Full example on action where:
1-2 page: paragraphs orphan works fine.
2-3 page: headers don't works.
Requirements:
HTML have one main div container.
Don't alter HTML.
Browser support isn't important (on my specific job).
I need some trick in CSS (no JS or Jquery, preferably)
I can't use page-break-before:always because I want that headers only go to next page when appears at bottom of page.

In typography an orphan is:
A paragraph-opening line that appears by itself at the bottom of a page or column, thus separated from the rest of the text.
However in HTML <h1> and <p> are different paragraphs then what you have to use is break-after property to tell layout engine to do not put a page break after that paragraph (with the side effect to move next paragraph up to previous page - if fit - or to move header to next page.
h1, h2 {
break-after: avoid-page;
}
Note about compatibility: break-after setting is a true working draft and even basic features are not widely supported (notably Internet Explorer 10 does). To workaround this you may use another property with similar meaning:
h1, h2 {
page-break-after: avoid;
}
Note that page-break-after applies to both page and columns. page-break-after isn't well supported by FF (it is a bug) then if compatibility is important and paragraph won't span across multiple pages you can workaround wrapping <h1> and <p> inside a container (let's say <section>) and then apply page-break-inside like this:
section {
page-break-inside: avoid;
}
IMO you should combine page-break-after and page-break-inside using page-break-inside with -moz prefix until it will fix that bug.

Related

break-inside: avoid doesn't work for basic example

I'm using Chrome v99 and a pretty basic usage of break-inside: avoid - but it does nothing.
Moderator: This is not a duplicate of this post and the 1 answer there isn't helpful.
My objective is to disallow the contents of all these divs from splitting at page breaks:
<div class="opt">
Here is my inline css:
<style media="screen" type="text/css">
#media print {
div.opt, table {
break-inside: avoid !important;
}
}
</style>
The full html is a bit lengthy but you can view the entirety here.
Simply press CTRL+P and observe that it page-breaks in the middle of divs with a class of opt - but it shouldn't because I'm using break-inside: avoid.
The example I linked to is very short and contrived, but my real scenario has many more sections and is dynamic, pulling from a database. So there's no way to know where the page is going to break relative to the divs. I just want the contents within those divs with that class to always stay together on the same page and never split across a page break. No div contents ever exceed a page, they are even shorter than my example.
Help, what am I doing wrong?
You have media=screen in the style tag...
Your print styles will only load when you're using a screen and not a printer
<style media="print" type="text/css">
div.opt, table {
break-inside: avoid !important;
}
</style>
When you fix it though it still seems to wrap onto multiple pages uglier but at least now you can play around with what print styles work

Should CSS "orphan" operate at line or block level?

I'm rendering HTML documents to PDF. Previously I was using Wkhtmltopdf, but it looks like Dompdf offers better support for page breaks, so I expect I will switch to that.
I'd like to apply some orphan control to my document, so I need to have a solid understanding of what orphans actually does. From W3C (source):
The orphans property specifies the minimum number of lines in a block container that must be left at the bottom of a page.
The example that is consistently offered around the web is this:
p { orphans: 3; }
This means that if there isn't space for three lines of paragraph text, a break is forced to the next page. I am rendering a document containing a lot of unordered lists, so for me it would be:
li { orphans: 2; }
However, I'd also ideally like to break an unordered list so that a bullet item block is not orphaned or widowed on its own. It would be nice to be able to do this:
ul { orphans: 2; }
That would ideally ensure that no item block could appear above or below a page break on its own. However browser/renderer support for this is patchy, and W3C above use the word "line" rather than "block". Thus, I imagine the above would just affect paragraph line control within list items, and would not affect whole list item blocks. If that is the case, is there a CSS way to do this?
As mentioned by liZe on the WeasyPrint issue tracker:
Orphans / Widows only work for line-boxes, not for block-like boxes.
Fortunately, you can define rules like:
li:last-child {
break-before: avoid;
}
li:first-child {
break-after: avoid;
}

CSS List Style has random space

I am trying to code a page, and for some reason i have a random css spacing issue for my list that i created. On the bottom right i have a random space between the list and its div.
I am styling it fine i think but my code is here at jsFiddle
and it works fine there for some reason. Any ideas?
If needed i can supply the entire page link.
I want that whole entire css list to span accross the entire div but it has a huge gap between the left wall of the div and its list.
The list on the page you link to needs to have its padding (and potentially its margin ... some browsers have different default styles) cleared. Here are some rules you could use to fix this:
#navlist {
list-style-type: none; /* Removes default list style */
margin: 0;
padding: 0;
}
I highly recommend getting the Firebug extension for Firefox. It makes debugging layout issues like this very easy. It also helps you see whether the style rules you are writing are being overridden by a more specific rule elsewhere in your style sheet.
As an aside, you shouldn't be using the center element. That element has been deprecated, and should be handled via your style sheet like so: text-align: center;

How do I avoid a page break immediately after a heading

I have an HTML 4.01/CSS 2.1 document that includes an H3 heading followed by a short (one line) paragraph block and then an unordered list with several items:
<h3>Heading!</h3>
<p>Some things:</p>
<ul>
<li>Thing one</li>
<li>Thing B</li>
<li>Thing 4</li>
</ul>
My problem is that when I print the document (or render it as a PDF using wkhtmltopdf), sometimes a page break will occur right after the heading, before the paragraph, which looks quite silly.
Is there a way to stipulate that page breaks should be avoided immediately after a header? (I'm not averse to HTML5/CSS3 solutions, if that simplifies things significantly.)
Note: following suggestions, I tried using the CSS property page-break-after: avoid. This doesn't really work in any WebKit or Mozilla based browsers, though.
This is an extremely hacky solution, but it works for me:
h1 {
page-break-inside: avoid;
}
h1::after {
content: "";
display: block;
height: 100px;
margin-bottom: -100px;
}
Basically I create an invisible element that increases the size of the <h1> without affecting the content after it. When page-break-inside: avoid is applied and the whole <h1> (including the hacky element cannot fit into the page) the browser is forced to carry the <h1> to the next page.
Since the CSS property page-break-after: avoid doesn't work in any WebKit or Mozilla based browsers, use the page-break-inside: avoid over the heading and an acceptable amount of the text:
CSS
<style type="text/css">
.nobreak {
page-break-inside: avoid;
}
</style>
HTML
<div class="nobreak">
<h3>Heading!</h3>
<p>Some things:</p>
</div>
<ul>
<li>Thing one</li>
<li>Thing B</li>
<li>Thing 4</li>
</ul>
If you used HTML 5 <article> and <header>, here's a hack that seems to work with Webkit, Blink and Gecko (tweak the value 8rem to match your needs):
article > header::before
{
content: "";
display: block;
height: 8rem; /* pretend that the header is at least 8rem high so this header cannot fit near the end of page */
margin-bottom: -8rem; /* however, reduce the margin the same amount so that the following content can stay in its usual place */
page-break-inside: avoid;
break-inside: avoid;
}
This works because pseudoelement ::before is rendered downwards from top of the header and browsers do support page-break-inside: avoid; well enough to actually reserve the space at the end of the page. It also uses the fact that browsers consider the height without margins when the space required is actually measured. I don't know if this is specified in any spec or just happens to match the real world browser behavior.
Some of the other answers suggest using ::after instead but in my experience that may result in cases where the container element <article> starts to render on the previous page. Using ::before seems to work better and the start of container element also seems to move. Obviously, the difference doesn't matter if your containing element doesn't have visible edges.
Note that because you have exactly one pseudo-element ::before you might not be able to use this hack if you want to apply some other styles for ::before. This hack requires that the ::before is rendered under the other content but transparent so it cannot contain visible content.
Additional things to consider:
The page-break nor page-break-inside do not work inside tables (display:table), display:grid nor display:flex. It's still unknown if this is caused by partial browser implementation or due CSS specification actually requiring this. In practice you need to use display:block for all the parent elements up to <html> or page breaks will happen anywhere.
You cannot limit the reserved space to height of full container element. For example, if the whole <article> in the above example is less than 8rem high, the element will still skip to next page because this hack blindly reserves space for 8rem before even trying to fit the <article> on the page.
However, in practice this works better than break-after:avoid or page-break-after:avoid due real world browser support. Also, the support for widows and orphans is really poor, so you may want to apply similar hack for <p> element, too. I would suggest 2rem or 3rem space for those.
When dealing only with lines inside a Paragraph, you could use the widows and orphans attributes in CSS. But unfortunately this will not bind your header to the Paragraph or the List. This because widows and orphans are not applied on block-like elements (like headers). See Should CSS "orphan" operate at line or block level?
I tried it since I've got stuck with the same problem. It seems to work when I print the Page from the Browser (Opera in my case) but not when I export the PDF with wkhtmltopdf.
Looks like putting all the elements that we don't want to be separated into a div and style this one with page-break-inside: avoid, like suggested in the accepted answer.
In my case where I have to display some headers and tabular data, I had to build a routine that finds the headers and then counts a certain amount of table-rows ahead and relocates the header and the table(s) into one div.
I recently worked on the pdf download story which was having dynamic rows of data in table format which include various charts images(tech used=>Angular + Spring + Thymleaf + Puppeteer) Some of the key points for handling page-breaks
Try to use <div></div>blocks instead of HTML tables
Do not use display: flex on the parent container on which you want page-break-inside: avoid(use float in child element)
.child1{ float: left; }
3.If you are rendering div in loop and page-break-inside: avoid; not working You should use this CSS hack to work on a particular div
<div class="parent-container">
<div class="child1"></div>
<div class="child2"></div>
</div>
.parent-container{
position: relative;
page-break-inside: avoid;
}
.parent-container::after {
content: "";
display: block;
height: 200px;
margin-bottom: -200px;
}

page-break-inside doesn't work in Chrome?

I have a bunch of paragraphs on a page:
<p> ... </p>
<p> ... </p>
<p> ... </p>
The CSS rule for those paragraphs is:
p {
margin: 20px 0;
page-break-inside: avoid;
}
Live demo: http://jsfiddle.net/KE9je/2/show/
If I understand the page-break-inside property correctly, the above should ensure that no paragraph is split between two pages. (A paragraph is either displayed on the "current" page, or if it doesn't fit completely, it's moved to the next page.)
This doesn't seem to work in Chrome. Open the demo, right-click the page, choose "Print...". You'll see a print preview - the fifth paragraph is split between page 1 and 2.
What am I doing wrong? How can I make this work in Chrome?
Actually, it DOES work in Chrome, and the solution is really silly!!
Both the parent and the element onto which you want to control page-breaking must be declared as:
position: relative;
Check out this fiddle (or in fullscreen)
This is true for:
page-break-before
page-break-after
page-break-inside
However, controlling page-break-inside in Safari does not work (in 5.1.7, at least)
I hope this helps!!!
This worked best for me:
.no-page-break {
display: inline-block;
width: 100%;
page-break-inside: avoid;
}
You can also specify the height if needed.
I've been fighting with this for a while and as well as follow the advice in the other answers I had to make sure that the element and all parent elements had the styling Display: block;.
I know this is an old question but Chrome has changed since it was originally answered and this may help.
It looks like page-break-inside:avoid works in Chrome based on the height of the element, so if you are floating a bunch of elements in a div, page-break-inside:avoid will not work.
It's possible to get around this by explicitly defining the height the element you don't want broken up. jQuery example:
$('#page_break_inside_avoid_element').height($('#page_break_inside_avoid_element').height());
According to SitePoint, Chrome is not supported here, only Opera (and IE 8 buggy)...
http://reference.sitepoint.com/css/page-break-inside
Other references:
http://www.webdevout.net
http://www.reddit.com/r/css/comments/jdeim/pagebreakinside_avoid_doesnt_work/
Stack Overflow threads:
Cross-browser support of `page-break-inside: avoid;`
"page-break-inside: avoid "- does not work
Google Chrome Printing Page Breaks
Which browsers support page break manipulation using CSS and the page-break-inside element?
Google Chrome Forum:
http://www.google.com/support/forum
I will not post the W3Schools link (due to general unreliability) but they also state it's only supported in Opera, for whatever it's worth.
I recently worked on the pdf download story which was having dynamic rows of data in table format which include various charts images(tech used=>Angular + Spring + Thymleaf + Puppeteer)
Some of the key points for handling page-breaks
Try to use <div></div>blocks instead of HTML tables
Do not use display: flex on the parent container on which you want page-break-inside: avoid(use float in child element)
.child1{
float: left;
}
3.If you are rendering div in loop and page-break-inside: avoid; not working
You should use this CSS hack to work on a particular div
<div class="parent-container">
<div class="child1"></div>
<div class="child2"></div>
</div>
.parent-container{
position: relative;
page-break-inside: avoid;
}
.parent-container::after {
content: "";
display: block;
height: 200px;
margin-bottom: -200px;
}
Check if the parent container display is not inline-block!!
If so, then it will never work! I waste few hours to figure it out.
Works in Chrome 87
For Bootstrappers, be aware that page-break-inside or others may not (highly) work under container or row or other classes of bootstrap even if you change manually the position property. When I exclude container and row, it worked like a charm!
I solved it: my problem was "a" parent div (not "the" parent div) set as display: flex.
I set it to display: block and it works.
I just tested this with a larger paragraph in IE9, Chrome 14 and Firefox 7, and it looks like only IE9 works as expected. You might have to resort to adding page breaks manually where you want them with
page-break-after:always
Of course that's only any good to you if you know the content length in advance.
What worked for me (in both FFox & Chrome, that is)
.container {
column-gap: .4em;
columns: 3;
padding: .4em;
}
.contained {
page-break-before: avoid;
page-break-inside: avoid;
page-break-after: always;
}
And that's it ; I didn't need position.
check if the parent(or top level container) display is flex ; remove it and try again;
it works for me in chrome71
Here is how I solved this while writing a css for printing.
For example, you put some pictures in an HTML file like this:
<div class="bottom">
<figure>
<img src="img01.jpg" alt="Front View">
<figcaption>Front View</figcaption>
</figure>
<figure>
<img src="img02.jpg" alt="Rear View">
<figcaption>Rear View</figcaption>
</figure>
</div>
And write the css like this:
.bottom figure{
page-break-inside: avoid;
}
Sometimes it won’t work as you expect, because the default value of display for most elements is block or inline, which is not ‘page-break friendly’. I usually change it like this:
.bottom{
display: contents;
}
This aims to disappear the container, making the child elements children of the element the next level up in the DOM.
As for your question, I suggest you to have a look at the display mode of the container of the paragraph to see whether it is set to block. If so, change it to contents and try again.
I hope this help.
After a huge digging, it seems to be a very silly, annoying and simple issue.
The key to fixing this issue is:
First, let's define what's parent and child.
Child: It's the element that we need to prevent/avoid cutting through in-between pdf pages
Parent: It's the direct parent/container of the child
Now we have the parent and the child very obvious, the next step is to give both parent and child some easy-to-implement rules. so let's do that
Parent rules
display: block;
Child rules
display: block; position: relative: page-break-inside: avoid;
That's it!
It Works for me, like this:
.print{position: absolute;}
.print p{page-break-inside: avoid}
Also page-break-inside: avoid may not work if one of parent elements has fixed height (say height: 1000px). I guess that's because browser is trying to fit content in specified height first and only then thinks about page breaking.
Changing to height: 100% fixed it for me.