Skip to content

GitLab

  • Menu
Projects Groups Snippets
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • pagedjs pagedjs
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 209
    • Issues 209
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
    • Requirements
  • Merge requests 4
    • Merge requests 4
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Monitor
    • Monitor
    • Incidents
  • Packages & Registries
    • Packages & Registries
    • Package Registry
    • Infrastructure Registry
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • pagedjs
  • pagedjspagedjs
  • Issues
  • #212

Closed
Open
Created Jun 07, 2020 by Boris Budini@kominoshja🛡Owner

Managing where on a page/column the break happens

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:

enter image description here

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.

enter image description here

If a new article starts in the bottom 40% of the page, I'd like that to be forced to the next page too.

enter image description here

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.

enter image description here

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.:

enter image description here

Bumping H1s off the page causes issues, the shim inflates, but pushes the heading into an invisible area, or a few other strange situations.

enter image description here enter image description here

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.


@JulieBlanc has been very helpful, and suggested:

h1 {
    break-before: avoid; 
}
h1 + p {
     orphans: 8;
}

Which works in pure text documents, in most situations.

But in situations where the the heading is exactly at the bottom of the page/column, there are no orphans for the layout engine to worry about.

image

Of if the element that comes after the h1 isn't a p, for example, an img, then it's also not useful:

image


Indesign has a concept of keep options which seem related, Latex has the needspace package/concept.

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.

Assignee
Assign to
Time tracking