CSS Paged Media: Cannot achieve desired breaking behaviour (break-after, break-before doing nothing)

Viewed 380

Here's the layout of the relative part of my document:

<!-- ↑ more sections -->
<section>
  <h2>Header 2</h2>
  <div class="subsection">
    <div><h3>Header 3</h3></div>
    <div>
      <h4>Header 4</h4>
      <div class="body-text"><!-- Parsed markdown text --></div>
      <h4>Header 4</h4>
      <div class="body-text"><!-- Parsed markdown text --></div>
      <!-- ↓ And so on... -->
    </div>
  </div>
  <div class="subsection">
    <div><h3>Header 3</h3></div>
    <div>
      <h4>Header 4</h4>
      <div class="body-text"><!-- Parsed markdown text --></div>
      <!-- ↓ And so on... -->
    </div>
  </div>
  <div class="subsection">
    <div><h3>Header 3</h3></div>
    <div>
      <h4>Header 4</h4>
      <div class="body-text"><!-- Parsed markdown text --></div>
      <!-- ↓ And so on... -->
    </div>
  </div>
  <!-- ↓ and so on... -->
</section>
<!-- ↓ more secitons -->

Which looks like:

And as for where I'd like page-breaks to be able to happen:

  • You cannot break between an h2 and the first .subsection;
  • You cannot break between an h4 and its .body-text;
  • You can break between a .body-text and the h4 following it;
  • You can break within a .body-text if it gets too long;
  • You can break between a .subsection and another .subsection

Here's what I've tried so far:

/* Borders to show where I do and do not want breaks in the following screenshot */
h2 {
  break-before: auto;   /* ✅ */
  break-after: avoid;   /* ❌ */
  border-top: 1px solid forestgreen !important;
  border-bottom: 1px solid red !important;
}

.subsection:first-of-type {
  break-before: avoid;  /* ❌ */
  break-after: auto;    /* ✅ */
  border-top: 1px solid red !important;
  border-bottom: 1px solid forestgreen !important;
}

h4 {
  break-before: auto;  /* ✅ */
  break-after: avoid;  /* ❌ */
  border-top: 1px solid forestgreen !important;
  border-bottom: 1px solid red !important;
}

.subsection:first-of-type h4 {
  break-before: avoid;  /* ❌ */
  border-top: 1px solid red !important;
}

.body-text {
  break-before: avoid;  /* ❌ */
  break-after: auto;    /* ✅ */
  border-top: 1px solid red !important;
  border-bottom: 1px solid forestgreen !important;
}

This seems to be fairly synonomous with what I've outlined above. However, I see the following once I go to print:

You can see that, even though I've been explicit with break-*: auto;, there is still a break between the Course Content Creator h4 and its following .body-text. What is stopping it from breaking at the green line immediately preceeding it (after the Web Application Development line)? Surely these two boxes should be glued together.

The only thing that seems to actually do… anything is using break-inside: avoid; on the sections:

section {
  break-inside: avoid;
  background-color: rgba(255, 0, 0, 0.25);
}
/* ↓ CSS from above... ↓ */

Clearly, this is not the correct way to go about things, since I very much do not want to avoid breaks inside of sections. It's just that this is the only thing that seem to affect how the document is actually printed.


I'm doing this in Chrome, version 83.0.4103.106. Firefox 77.0.1 performs the same way.

If it makes a difference, The .subsections are actually Vue components, which are slotted into each section's component. I don't see how this would be the problem, though, since I've double-checked with Chrome DevTools that even through all the CSS scoping that happens, every CSS property is applied to the correct element. In any case, the source code for this project is fully visible here: github.com/matthew-e-brown/resume.

2 Answers

break-inside: avoid on a section does not imply a section can never have a page-break. It implies that it should be avoided if possible.

It also looks like you do want to allow pagebreaks inside the .subsection divs, opposed to inside the section. page-break: avoid on the .subsections is what caused them to go to the next page when they don't fit.

/*prevent page breaking inside section, when a section doesn't fit it will display on the next page */
section {
  break-inside: avoid;
}
/*try not to break between h2 and section*/
h2 + .subsection {
  break-before: avoid;
}

How to think about page-breaks

I think it may be useful to describe how I think about the main page break options. It may help your understanding.

page-break: inside: glues together all the content inside this element. It will try to act as a single block.

break-before: avoid: glues the element before it to the current element so they try to act as a single block.

break-after: avoid: glues the element after it to the current element so they try to act as a single block.

After giving up for just about two years and only just now deciding to look into this again, I've found my answer. The problem comes from the fact that my document uses CSS Grid to lay content out side-by-side. As per this answer, the W3 specification for this sort of behaviour is still in the candidate stage.

So, it looks like I was just a little bit ahead of the curve. At the very least, there doesn't seem to be anything wrong with the CSS code itself

Related