Making Text Columns Behave Like eBook Pages
Jason Pamental’s Web Fonts & Typography News digs into a deceptively tricky problem: how to get swipeable, page-like text columns in his digital book experience on mobile. The first step is almost too easy—a single line makes columns add themselves horizontally as content overflows:
columns: 100vw auto;
The trouble starts when you add a little formatting to those columns:
main {
columns: 100vw auto;
column-gap: 2rem;
overflow-x: auto;
height: calc(100vh - 2rem);
font: 120%/1.4 Georgia;
}
On desktop, this effect is unnecessary anyway—media queries can keep it mobile-only. But on mobile, the scrolling is janky. Adding -webkit-overflow-scrolling: touch; smooths things out, but only marginally. The columns no longer feel like pages because they don’t snap into position. That’s what scroll-snap is meant to fix, but there’s a catch:
Unfortunately it turns out you need a block-level element to which you can snap, and the artificially-created columns don’t count as such.
Scroll snapping demands actual block-level elements, like <div>s, arranged in a flex row:
main {
display: flex;
}
main > div {
flex: 0 0 100vw;
}
But that approach hits a wall immediately: you can’t know in advance how many <div>s the content will need, and there’s no way to flow text naturally from one <div> to the next. That’s the feature CSS regions was supposed to provide but never did. To make this work purely in CSS, you’d need to either:
- Let scroll snapping target CSS columns directly
- Introduce something like CSS regions that can auto-generate the necessary block-level elements on demand
Both are unavailable in current browsers.
Rather than resort to heavy scrolljacking, Pamental took a lighter JavaScript approach. He calculates how many “pages” the CSS column layout produces, then inserts spacer <div>s into the scrolling container—one per page, each exactly page width. Those spacers become the snap targets. The result is available now as an optional setting on the book site, and it works without hijacking the scroll experience.



