How Do I Avoid A Page Break Immediately After A Heading
Heading!<
Solution 1:
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.
Solution 2:
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>
Solution 3:
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
norpage-break-inside
do not work inside tables (display:table
),display:grid
nordisplay: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 usedisplay: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 than8rem
high, the element will still skip to next page because this hack blindly reserves space for8rem
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.
Solution 4:
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.
Solution 5:
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;
}
Post a Comment for "How Do I Avoid A Page Break Immediately After A Heading"