Skip to content

Instantly share code, notes, and snippets.

@12joan
Last active December 30, 2025 22:22
Show Gist options
  • Select an option

  • Save 12joan/2ac32dc4d4e105b3e6eb1fab9f249c1c to your computer and use it in GitHub Desktop.

Select an option

Save 12joan/2ac32dc4d4e105b3e6eb1fab9f249c1c to your computer and use it in GitHub Desktop.
Page breaks using CSS float and clear

Page breaks using CSS float and clear

Demonstrates how the float and clear CSS rules can be used to position page breaks in an editable document. This is the same technique that is used by Tiptap's PageKit extension.

View on CodePen

License

This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to https://unlicense.org/

<main contenteditable>
<!--
The following two DIV elements comprise a single page break. They must be
placed at the start of the document in order for the page break to be
positioned correctly.
Note that assistive technology will read these first regardless of the page
break's visual position in the document. It may be possible to mitigate
this using the `aria-flowto` DOM attribute.
Additional page breaks may be inserted by using additional `.before-break`
and `.break` elements, in which case the heights of the `.before-break`
elements are cumulative. The heights of previous `.break` elements have no
effect on the positions of subsequent `.break` elements unless a `clear`
CSS rule is used on `.before-break`.
-->
<div class="before-break" contenteditable="false">
</div>
<div class="break" contenteditable="false">
<p>This is a page break.</p>
<label>
<input type="checkbox" />
Follow mouse (press escape to toggle)
</label>
</div>
<h1>HTML Ipsum Presents</h1>
<p><strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.</p>
<h2>Header Level 2</h2>
<ol>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ol>
<blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.</p>
</blockquote>
<h3>Header Level 3</h3>
<ul>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ul>
<p><strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.</p>
<h2>Header Level 2</h2>
<ol>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ol>
<blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.</p>
</blockquote>
<h3>Header Level 3</h3>
<ul>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ul>
</main>
const main = document.querySelector('main');
const beforeBreak = document.querySelector('.before-break');
const breakEl = document.querySelector('.break');
const followMouseCheckbox = document.querySelector('input');
function isFollowingMouse() {
return followMouseCheckbox.checked;
}
document.addEventListener('mousemove', event => {
if (isFollowingMouse()) {
const offset = event.clientY - main.offsetTop - breakEl.clientHeight / 2;
beforeBreak.style.height = offset + 'px';
}
});
document.addEventListener('keydown', event => {
if (event.key === 'Escape') {
followMouseCheckbox.checked = !followMouseCheckbox.checked;
}
});
/* Purely aesthetic */
main {
max-width: 720px;
margin: 0 auto;
}
/**
* This element serves to push the break element down by the required amount.
* The `float: left` CSS rule, combined with the fact that it has a width of 0,
* means that this element has no visible effect by itself.
*
* Try uncommenting the `width: 20px` and `background: red` CSS rules to
* visualise this.
*
* You can also use `margin-top` instead of `height`, which has the same effect
* of pushing the break element down.
*
* If multiple page breaks are used, a `clear: left` CSS rule can be added to
* this element if the heights of previous page breaks should be taken into
* consideration when applying the positions of subsequent page breaks.
*/
.before-break {
height: 140px;
float: left;
/* width: 20px; background: red; */
}
/**
* This is the page break element. The `clear: left` CSS rule means that this
* element must appear below the floating `.before-break` element.
*
* Try removing the `clear: left` CSS rule. This causes the element to ignore
* the height of the `.before-break` in the same way that regular page content
* does.
*
* The direction of the `clear` CSS rule must match the direction of the
* `.before-break` element's `float`, or it can be set to `both`.
*
* The `float: left` CSS rule ensures that page content flows around this
* element. To better visualise this, try changing the width to `50%`. This
* causes the element to behave more like a traditional floating element.
*
* Try removing the `float: left` CSS rule. The element remains at the same
* position as before due to the `clear` CSS rule, but the page content no
* longer flows around it.
*
* There is no need for the direction of the `float` CSS rule to match that of
* this element's `clear` CSS rule or the `.before-break` element's `float` CSS
* rule. However, this element's `float` CSS rule must match the direction of
* the `.before-break` element's `clear` CSS rule if such a rule is used to
* support multiple page breaks.
*/
.break {
clear: left;
float: left;
width: 100%;
/* Purely aesthetic */
background-color: lightgrey;
padding: 1rem;
box-sizing: border-box;
text-align: center;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment