What goes wrong
If there is an element with a CSS property break-before or break-after that also contains children, whose content ends up being split by the extractOverflowingContent-method, the algorithm will ignore the value set to this breaking-*-property.
The cause
The moment a single region can not contain all of the content (for whatever reason) extractOverflowingContent is being invoked. Once a suitable cut-off point has been detected, it will then traverse the content in the region bottom-up in order to detect any elements which have a break-before property set (or others, but that is irrelevant here).
It does so by executing the following code:
|
var current = r.endContainer; if(current.hasChildNodes()) { if(r.endOffset>0) { current=current.childNodes[r.endOffset-1] } }; |
|
var first = r.endContainer.firstChild; |
|
do { |
|
if(current.style) { |
|
|
|
if(current != first) { |
|
if(/(region|all|always)/i.test(cssCascade.getSpecifiedStyle(current,'break-before',undefined,true).toCSSString())) { |
|
r.setStartBefore(current); |
|
r.setEndBefore(current); |
|
dontOptimize=true; // no algo involved in breaking, after all |
|
} |
|
} |
|
|
|
if(current !== region) { |
|
if(/(region|all|always)/i.test(cssCascade.getSpecifiedStyle(current,'break-after',undefined,true).toCSSString())) { |
|
r.setStartAfter(current); |
|
r.setEndAfter(current); |
|
dontOptimize=true; // no algo involved in breaking, after all |
|
} |
|
} |
|
|
|
} |
|
} while(current = cssRegionsHelpers.getAllLevelPreviousSibling(current, region)); |
The backward traversal happens by invoking a helper-method cssRegionsHelpers.getAllLevelPreviousSibling on line 560:
|
} while(current = cssRegionsHelpers.getAllLevelPreviousSibling(current, region)); |
This method is pretty straightforward:
|
getAllLevelPreviousSibling: function(e, region) { |
|
if(!e || e==region) return null; |
|
|
|
// find the nearest ancestor that has a previous sibling |
|
while(!e.previousSibling) { |
|
|
|
// but bubble to the next avail ancestor |
|
e = e.parentNode; |
|
|
|
// dont get over the bar |
|
if(!e || e==region) return null; |
|
|
|
} |
|
|
|
// return that sibling |
|
return e.previousSibling; |
|
}, |
It will return the previous sibling, unless it has none. In that case it moves up to its parent and returns its previous sibling. This however means the the actual parent-element is completely ignored. And this is why the problem described above occurs.
An example
Let's say we have content that looks like this:
...
<p>....</p>
<table>
...
<tr>..</tr>
<tr>..</tr>
...
</table>
and some styling that looks like this:
table { break-before: always }
If the table ends up overflowing a region, then a TR-element will end up being the target from which the algorithm will start looking for elements with a break-*-property set.
However, the getAllLevelPreviousSibling-method will skip over the table-element and move directly on to the paragraph preceding it. In effect, the table will not end up being moved to the subsequent region, it will be cut in two instead.
Possible fix
Taking the actual parent element also into account, instead of skipping it, should resolve this.
What goes wrong
If there is an element with a CSS property
break-beforeorbreak-afterthat also contains children, whose content ends up being split by theextractOverflowingContent-method, the algorithm will ignore the value set to thisbreaking-*-property.The cause
The moment a single region can not contain all of the content (for whatever reason)
extractOverflowingContentis being invoked. Once a suitable cut-off point has been detected, it will then traverse the content in the region bottom-up in order to detect any elements which have abreak-beforeproperty set (or others, but that is irrelevant here).It does so by executing the following code:
css-regions-polyfill/src/css-regions/polyfill.js
Lines 538 to 560 in d40c91b
The backward traversal happens by invoking a helper-method
cssRegionsHelpers.getAllLevelPreviousSiblingon line 560:css-regions-polyfill/src/css-regions/polyfill.js
Line 560 in d40c91b
This method is pretty straightforward:
css-regions-polyfill/src/css-regions/lib/helpers.js
Lines 17 to 33 in d40c91b
It will return the previous sibling, unless it has none. In that case it moves up to its parent and returns its previous sibling. This however means the the actual parent-element is completely ignored. And this is why the problem described above occurs.
An example
Let's say we have content that looks like this:
and some styling that looks like this:
If the table ends up overflowing a region, then a TR-element will end up being the target from which the algorithm will start looking for elements with a
break-*-property set.However, the
getAllLevelPreviousSibling-method will skip over thetable-element and move directly on to the paragraph preceding it. In effect, the table will not end up being moved to the subsequent region, it will be cut in two instead.Possible fix
Taking the actual parent element also into account, instead of skipping it, should resolve this.