I have a 2 column layout that is destined for print. h2–5 are within the column and h1s span both columns. I'm using Paged.js for pagination.
These two pages show acceptable layouts:
But If there's a situation where a heading is at the bottom of a column, I'd like the heading to be forced to the top of next column.
If a new article starts in the bottom 40% of the page, I'd like that to be forced to the next page too.
For h2 and below I inject a div above the heading that, if the heading is at the bottom of its column, I inflate it to push into the next column.
This seems to do the job for h2–5 because they're inside a flow that's managed by the browser. But only if they're in the left column; if they're in the right, they get bumped off the page. E.g.:
Bumping H1s off the page causes issues, the shim inflates, but pushes the heading into an invisible area, or a few other strange situations.
The first image shows the heading that is present in the second image, shimmed off the page.
The following (slightly simplified) markup is what generates page 11 (right, second image)
<div class="the-articles">
<article class="architectural-review.com paper-story noted">
<p>
No question, Rem is a genius. Nonetheless, his wake is toxic: stained by
Randian egos (both triumphal and crushed), the intense interpersonal
competition, and the exploitation of intellectual and manual labour. How
does it all end, you wonder. In some ways, Tomas Koolhaas’s documentary
was a preemptive eulogy. Death is present in every shot, tugging at the
great man’s sleeve. The film is also suffused by an intense melancholy. It
is the peculiar sadness of endings: when a family line is extinguished,
when change erases beauty and meaning, when an entire world order
disintegrates.
</p>
<p>
Starchitects are still with us, even though their era is over. Koolhaas
himself called time on it in the mid-2000s. It is no contradiction to
honour them, while admitting that we must give ourselves permission to
abandon the figure of the heroic architect, and along with it the Western
blueprint for greatness that Koolhaas has so relentlessly and obsessively
perfected.
</p>
<div class="tail-meta">
From:
<span class="url"
>https://www.architectural‑review.com/essays/reputations/rem‑koolhaas‑1944/10037224.article</span
>
</div>
<!-- SHIM IS HERE -->
<div class="shim-between-articles" style="height: 181.944px;"></div>
</article>
<article id="2415273718" class="newyorker.com paper-story noted">
<h1 class="article-title" id="h2415273718">
Love Is Not a Permanent State of Enthusiasm: An Interview with Esther
Perel
</h1>
</article>
</div>
I'm doing the shim-inflation inside afterPageLayout
, it calls this function:
function identifyTooCloseToBottomHeading(
theHeading,
pageCutoffPercentage,
page,
pageFragment
) {
try {
if (theHeading !== null && theHeading !== undefined) {
const pageBox = page.element.getBoundingClientRect();
const headingBox = theHeading.getBoundingClientRect();
const pdelta = pageBox.bottom - headingBox.bottom;
const botPC = pdelta / pageBox.height; //Gives a % up the page. I.e. 100% is the top
const cutPC = pageCutoffPercentage[theHeading.tagName.toLowerCase()];
const oneRem = parseFloat(
getComputedStyle(document.documentElement).fontSize
);
if (botPC < cutPC) {
console.log("at risk", theHeading);
if (theHeading.previousElementSibling) {
AdjustShimSize(oneRem);
} else {
const thisArticle = theHeading.parentElement;
const prevArticle = thisArticle.previousElementSibling;
const shim = prevArticle.querySelector(".shim-between-articles");
const topMetaBox = thisArticle
.querySelector(".top-meta")
.getBoundingClientRect();
shim.style.height = `${
theHeading.getBoundingClientRect().height + topMetaBox.height
}px`;
}
}
}
} catch (e) {
console.log(e, theHeading);
}
function AdjustShimSize(oneRem) {
const shim = theHeading.previousElementSibling;
// calculate the height that it needs to be
try {
const shimBox = shim.getBoundingClientRect();
const container = shim.closest(".the-articles");
const containerBox = container.getBoundingClientRect();
// logShimDetails(theHeading, container, shimBox, nextElBox, containerBox, oneRem);
shim.style.height = `${containerBox.bottom - shimBox.bottom - oneRem}px`;
console.log("shimmed", theHeading);
} catch {
console.log("trouble with", theHeading);
}
}
}
This seems like it ought to work, but it's not very elegant. I suspect that there's something that I could be doing with the breaktoken
? Is there a correct way to do this?
for the H1s, I have also tried adding a class to the article above, depending on how many lines would be needed to bump the heading to the next page. I.e. a series of css rules:
.n-line-fat-bottom-20 {
margin-bottom: calc(var(--wp-line-height) * 20) !important;
}
.n-line-fat-bottom-22 {
margin-bottom: calc(var(--wp-line-height) * 24) !important;
}
and then applying the class at the same point in the Paged.js lifecycle. It has similalry unhelpful results.
If I knew ahead of time which headings would need to break, I could give them a break-before: column;
or break-before: page;
rule, but by content isn't known ahead of time. Adding these rules after the fact doesn't seem to work with the lifecycle of paged.js. I suspect that it is a lifecycle issue, as pushing the content off the page should cause a reflow of the next page if I was doing it at the right point/correct handler.
It is CSS property that help to define how a elements on a page will look when printed. This makes the print of the document more book-like. page-break isn’t a directly usable property but it contains three properties that can be used as per requirement: page-break-before: adds a page break before an element
Adding page breaks also improves the performance of large reports when they are processed. A rendered page is displayed while the rest of the pages are rendered in the background. This allows you to begin viewing the initial pages of the report while waiting for additional pages to become available.
This makes the print of the document more book-like. page-break-inside: sets whether the page break should be avoided or not inside an element. It can be applied wherever required, inside the table, before or after the table or before or after a row, and even within a row.
When creating a script or library that is specifically aimed at extending the functionality of paged.js, it is best to use hooks and a handler class. Paged.js has various points in the parsing of content, transforming of CSS, rendering, and layout of HTML that you can hook into and make changes to before further code is run.
Hi to solve this problem I added a new component and gave it the necessary height to send the content in new page/column this is my raw implementation for my use case:
const attribute = node?.getAttribute('data-pdf-break-past');
const pageHeight = 967;
let maxHeightValueBeforeBreak = pageHeight;
if (attribute) {
maxHeightValueBeforeBreak = (pageHeight * +attribute) / 100;
}
const distanceToTop = node.getBoundingClientRect()?.top + window.scrollY;
const contentHeightInPage = distanceToTop % pageHeight;
const marginToSet = pageHeight - contentHeightInPage;
if (
(attribute && contentHeightInPage > maxHeightValueBeforeBreak) ||
node.className.includes('pdf-break-before')
) {
const newNode = document.createElement('div');
newNode.style.height = `${marginToSet}px`;
node.parentNode?.insertBefore(newNode, node);
}
I've used the Dom manipulation after that Paged.js has parsed the content.
note that margin or padding are not used because can cause issues with the library(weird behaviour while page break occurs).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With