v154 · scroll-marker-group · ::column composition
Column pager
The spec's most interesting sentence: when a ::scroll-marker originates from a ::column fragment, tabs mode gives the tabpanel role to the column's originating element. In other words: a plain flowing article, fragmented into pages by CSS multicol, becomes a paged, tabbed reader whose page dots are derived — grow the type and the browser re-paginates and re-derives the dots, roles and focus order, with no element per page in the markup.
A reader that derives its own pager
Fragmentation is pagination
Multicol has always chopped a flow of text into column boxes; what it lacked was any way to travel between them when they overflow horizontally. Give the container a fixed height and column-fill: auto, and the columns march off to the right — a book, waiting for a pager.
The carousel primitives supply the pager. Each generated ::column fragment can carry a ::scroll-marker, and the markers collect into the container's ::scroll-marker-group. The dots below this text are exactly that: one per column box, none in the markup.
Modes finish the job. With scroll-marker-group: after tabs, the group is a tablist and each dot a tab — and because the panels here are column fragments rather than elements, the spec routes the tabpanel role to the fragments' originating element. Assistive technology sees a coherent paged widget over what is, in the DOM, one run of prose.
Now resize the type with the slider above. The browser re-fragments the text into a different number of columns, and the marker group re-derives itself: more pages, more dots, same zero lines of pagination script. That is the promise of deriving UI from layout instead of mirroring layout in script.
The rule
.reader {
columns: 1; /* fragment the article */
column-fill: auto;
height: 15rem;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-marker-group: after tabs; /* pager = tablist */
}
.reader::column { scroll-snap-align: center; }
.reader::column::scroll-marker { content: ""; /* one dot per page */ }
.reader::column::scroll-marker:target-current { background: black; }
JavaScript cannot enumerate ::column fragments, so the page count above is measured honestly from geometry (scrollWidth / clientWidth) — it is a readout of what the fragmentation produced, not a driver of it.