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;
}
Related
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.
Is it possible with CSS(3) to visually/textually highlight line breaks, which were automatically inserted by browsers? Something like ↻ at the end of each wrapped line.
With sourcecode it's important to see where lines were wrapped, since newlines can be significant. Letting the user scroll horizontally isn't a good idea neither …
As far as I know, there is only way to do this using pure CSS, via the :first-line pseudo-element
Concept
Add a "visual indication" to every element, by default.
Select every :first-line element, to reset the styles.
Demo: http://jsfiddle.net/djpTw/
<code>
<div class="line">Too much code at one line. Learn to write shorter lines!</div>
<div class="line">Lonely line.</div>
...
</code>
CSS:
code {display: block; width: 150px;} /* <-- Not interesting, just for testing*/
code .line { color: red; /* Visual indication */ }
code .line:first-line { color: #000; /* Default color */ }
The demo is rendered as (black by default, red as "visual indication"):
Sadly, this is not possible in pure CSS. I suspect you might be able to fake it using a tall thin graphic attached to the bottom right with no glyph in the bottom and then glyphs proceeding up as far as your tallest reasonable run-on, with the glyph spacing carefully coordinated to your line-height.
I have a <div> styled like a box:
.box {
border:2px solid #ccc;
background:#eee;
padding:1em;
margin:1em;
}
In this box, there could be any number of any type of child elements in any order:
<div class="box">
<h3>Howzit goin</h3>
<p>Here comes a list:</p>
<ul>
<li>I don't know what</li>
<li>this box will contain</li>
<li>but it could be anything</li>
</ul>
</div>
Most or all of the child elements inherit bottom margin of various lengths from the base typography stylesheet:
/* Example global typography */
p {margin:0 0 1.5em;}
ul {margin:0 0 2.5em;}
Which produces output like this:
...but we want to normalize the "padding" of the box so that it appears equal on all sides:
.box :last-child would be too easy, this has to work in at least IE8 as well as
modern browsers (but it could be used in conjunction with an IE-only method).
I don't want to use extra markup or javascript.
Is there any other CSS trick I can use to get the output I want?
Fiddle: http://jsfiddle.net/yuXcH/1/
As you can read in this question, even if it's about 2 years old, there's no "easy" way to do this in IE8 (the other thread is just about IE6/7, but things haven't changed - IE8 doesn't support :last-child either).
The best way, in my opinion, is to manually add a class last-child to your last child so you can do:
.box .last-child{ margin-bottom: 0; }
The alternative is using javascript, which is easier if you have a lot of boxes. With jQuery, it would just look like this:
$(function(){
$(".box :last-child").css("margin-bottom","0");
})
The only "pure CSS" solution I can think of is changing all of your padding/margins to always result in a box with same padding on all sides like Lollero suggested, but this will, compared to your previous solution, result in different margins between the elements inside of the box.
I would probably compensate the extra space by having padding or margin in both top and bottom.
http://jsfiddle.net/lollero/yuXcH/2/
Also some padding change in top and/or bottom of the parent element can be used.
http://jsfiddle.net/lollero/yuXcH/3/
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.
You are aware of the age-old problem: Containers containing floated elements don't automatically expand their height to enclose their children.
One approach to fix this is the "clearfix" which adds a number of CSS rules to ensure a container stretches properly.
However, just giving the container overflow: hidden seems to work just as well, and with the same amount of browser compatibility.
According to this guide, both methods are compatible across all browsers that are important today.
Does this mean that "clearfix" is deprecated? Is there any advantage left in using it over overflow: hidden?
There is a very similar question here: What is the different between clearfix hack and overflow:hidden vs overflow:auto?
but the question isn't really answered there.
You can pretty much use overflow: hidden all the time.
But, there are exceptions. Here's an example of one:
Overflowing a container div horizontally but not vertically
The question there was:
There's a fixed height on this: http://jsfiddle.net/je8aS/2/
Without the fixed height: http://jsfiddle.net/thirtydot/je8aS/5/
How to clear the floats without using a fixed height?
overflow: hidden doesn't work: http://jsfiddle.net/thirtydot/je8aS/6/
You have to use some other method of clearing floats, such as clear: both:
http://jsfiddle.net/je8aS/3/
The clearfix class also works: http://jsfiddle.net/thirtydot/je8aS/11/
Here's a more important example of when you can't use overflow: hidden:
http://fordinteractive.com/misc/overflow/
That's not to say that clearfix is the only alternative - display: inline-block cleanly fixes that example:
http://jsbin.com/ubapog
As mentioned in another answer the downside to hidden is that it will, surprisingly ermm hide things like dropdown menus. However there is another way to contain with one line, by floating the parent container. This generally works where overflow: hidden has a downside, and also floating helps with a lot of legacy IE issues, again especially in lists. If you can use a width then I would use a "float in a float", or display: inline-block.
I'm not saying the "clearfix" has no use - but to me it's too widely entrenched into CMS themes (like Wordpress and Drupal) that I think in a lot of cases it's used too much and on divs that don't actually need to be cleared or contained.
I can't actually think of a situation where I can't use either overflow or float, over clearfix, but my brain's in holiday mode - but as it, clearfix, is a copy/paste solution that's sometimes the easiest thing to recommend, however it has to be the one which sets hasLayout for IE, which of course both overflow and float do too now as well.
added
this has just come up again: and brain not in holiday mode..
I'm really starting to think yes, clearfix is not necessary (at least I haven't yet found an example where it is) even #thirtydot's example above can be worked around with display: inline-block and still have IE6 support, the container having a fixed width has the IE7 and below hasLayout requirement, and by making it an inline-block for all other browsers it can be centered and the "offset" sticky-out elements will work fine while the container does stretch vertically
Example
I've also seen reference to a new improved clearfix for those collapsing margins using :before as well as :after in the clearfix hack, but unless I'm missing something the the demo is flawed - there is uneven whitespace in the pre elements and the "clearfixed" boxes do not actually contain any floats, as soon as you do float the elements in them, each method performs the same.
Note margins on pre elements don't react the same as others anyway (so try it with padding instead of margin to see the same picture while testing).. and there is also another IE "foible" whereby IE doesn't contain margins properly if they're not explicitly specified and in the demo there is explicit margins on the h2 but not the p so all things being equal a clearfixed element as demo'd by TJK in that page is artificially forcing the containment of the margins on a normal block element, much the same way as 1px top/bottom padding would do because browsers do this differently anyway!
If you do then float the elements inside those containers (the point of clearing anyway) - the margins do then contain as you would probably like them to, as they would if inside a new Block Formatting Context - without any extra :before part to the hack, all clearfix variations work equally well!
See the demo reloaded
So to my mind there is no need for this "clearfix" way anymore, simply find the best way to create that new Block Formatting Context, using haslayout for older IE's.. the properties for both are the same!
as TJK does point out in his article : http://www.yuiblog.com/blog/2010/09/27/clearfix-reloaded-overflowhidden-demystified/
Better alternatives
If you can apply a width to the
element containing floats, then your
best option is to use:
display: inline-block; width: <any
explicit value>;
I think that's fair and even with 100% elements which might need padding, you can do it in conjunction with box-sizing
.clearfix {
display: inline-block;
width: 100%;
*width: auto;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
overflow:hidden is very 'powerful' (I've been using it for several years, and I agree to what David said) but at the same time exposes to a problem. If i.e. inside the container you have some abs elements that you have to drag and drop outside of it, u won't be able to see them outside the container. In this particular case u need to use that 'clearfix' trick ;)
Yes, it's "deprecated" by CSS Display L3:
Created the flow and flow-root inner display types
to better express flow layout display types and to create an
explicit switch for making an element a BFC root. (This should
eliminate the need for hacks like ::after { clear: both; } and
overflow: hidden that are intended to accomplish this purpose.)
So now, the proper way is
display: flow-root;
Sadly it's a recent addition, so browsers haven't implemented it yet.
I've been recommending the overflow: hidden method for many years. It is widely supported.
I recently discovered to my pleasant surprise that overflow:hidden works perfectly nowadays. I had been using the clearfix method up until around 6 months ago and it is quite bloated in comparison.
Note: Make sure you have the correct DOCTYPE set if you're just testing. Caught me out a few times and I always forget!
In IE9 for instance the following just won't work without <!DOCTYPE html> at the top.
<!DOCTYPE html>
<html>
<style>
#bottom_panel {
overflow: hidden;
background: orange;
border:1px solid red;
}
#bottom_panel .col1 {
background: red;
float: left;
width: 100px
}
#bottom_panel .col2 {
background: yellow;
float: left;
width: 70px
}
#bottom_panel .col3 {
background: green;
float: left;
width: 150px
}
.clear {
clear: both;
}
</style>
<div id="bottom_panel">
<div class="col1">this is col 1</div>
<div class="col2">this is col 2. It's taller than the other columns because it's got more text in ot</div>
<div class="col3">this is col 3</div>
</div>
<div>
This should not be floating around! Should be underneath the columns!
</div>
</html>
I wouldn't say that clearfixing is deprecated. However, I would say that most versions of the clearfix currently being used are outdated.
According to the experts, this is the version your should use today:
.clearfix:after {
content: "";
display: table;
clear: both;
}