Get affordable and hassle-free WordPress hosting plans with Cloudways — start your free trial today.
Experimental: Check browser support before using this in production.
The ::scroll-marker-group
pseudo-element holds the scroll markers generated by the ::scroll-marker
pseudo-element. When clicked on, these scroll markers scroll users to a corresponding scroll target within a scroll container in a scroll-snapping fashion. All in all, scroll markers give users an additional way to navigate overflow content.
You can select ::scroll-marker-group
like this:
.scroll-container::scroll-marker-group {
/* ... */
}
When you ::scroll-marker
like this (these get put inside ::scroll-marker-group
):
.scroll-target::scroll-marker {
/* ... */
}
…the HTML result gets rendered like this:
<ul class="scroll-container">
<!-- Five scroll targets -->
<li class="scroll-target"></li>
<li class="scroll-target"></li>
<li class="scroll-target"></li>
<li class="scroll-target"></li>
<li class="scroll-target"></li>
<::scroll-marker-group>
<!-- Five scroll markers -->
<::scroll-marker>
<::scroll-marker>
<::scroll-marker>
<::scroll-marker>
<::scroll-marker>
</::scroll-marker-group>
</ul>
Scroll markers are ideal for carousels, scroll snapping components, and any other components where you’d scroll overflow content. You can combine them with ::scroll-button
s, other scroll-based pseudo-elements, other scroll-based features, and a wide range of CSS features in general. They’re quite versatile.
::scroll-marker-group
and ::scroll-marker
are fully accessible, too. Users can easily navigate the scroll markers with a keyboard and other types of assistive technologies, and screen readers will label them descriptively right out of the box.
Syntax
::scroll-marker-group {
/* ... */
}
Basic usage
To select all ::scroll-marker-group
s:
::scroll-marker-group {
/* ... */
}
To select the ::scroll-marker-group
of a specific scroll container:
.scroll-container::scroll-marker-group {
/* ... */
}
There are some additional requirements, though:
- The container must be a scroll container (i.e., its
overflow
property must not compute to visible). - The scroll container must set the
scroll-marker-group
property to eitherbefore
orafter
. - The scroll markers must have valid
content
properties (or they won’t show).
Therefore, your CSS should start off something like this:
.scroll-container {
/* Required */
scroll-marker-group: after; /* before | after */
&::scroll-marker-group {
/* ... */
}
.scroll-target::scroll-marker {
/* Required */
content: ""; /* Any valid value */
}
}
The purpose of scroll-marker-group
is to help you to accessibly match the tab order to the visual order, so if the scroll markers appear before the scroll component’s content (roughly, at least), you’d use the before
value. Otherwise, you’d use after
. The default value is none
, so if you don’t set scroll-marker-group
to either before
or after
, the ::scroll-marker-group
pseudo-element and the scroll markers within it simply won’t appear.
Example: Carousel
The example below is a fully-functional carousel that you can navigate using scroll markers. The ::scroll-marker-group
pseudo-element uses anchor positioning to position itself relative to the scroll container, which is probably the best way to go about it, but any method of alignment should work fine. And since the scroll markers are positioned at the bottom, the scroll-marker-group
property is set to after.
It also uses Flexbox to lay out the scroll markers within.
<ul class="carousel">
<li style="background:hsl(10 70% 50%)"></li>
<li style="background:hsl(30 70% 50%)"></li>
<li style="background:hsl(50 70% 50%)"></li>
<li style="background:hsl(70 70% 50%)"></li>
<li style="background:hsl(90 70% 50%)"></li>
</ul>
.carousel {
/* The width */
--carousel-width: 100vw;
width: var(--carousel-width);
/* The height is half the width */
aspect-ratio: 1 / 0.5;
/* Implies flex-direction: row */
display: flex;
li {
/* Give carousel items the same width */
width: var(--carousel-width);
/* Prevent flexbox from overwriting said width */
flex-shrink: 0;
}
/* Show only one carousel item */
overflow: hidden;
/* Turn the carousel into an anchor */
anchor-name: --carousel;
/* Enable smooth scrolling */
scroll-behavior: smooth;
/* Place after the content */
scroll-marker-group: after;
&::scroll-marker-group {
/* Space the markers apart */
display: flex;
gap: 10px;
/* Anchor it to the carousel */
position: fixed;
position-anchor: --carousel;
/* Anchor it horizontally */
justify-self: anchor-center;
/* Anchor it near the bottom */
bottom: calc(anchor(bottom) + 10px);
}
li::scroll-marker {
/* Stylized markers */
content: "";
width: 10px;
height: 10px;
border-radius: 10px;
border: 1px solid black;
}
/* The currently selected marker */
li::scroll-marker:target-current {
background: black;
}
}
Example: Tabs
The following example is fundamentally the same. The key difference is that the scroll markers are styled as tabs and positioned at the top, so as you’d expect this means that the scroll-marker-group
property is set to before
this time.
You shouldn’t have any trouble choosing between before
and after
. Even in the example below where ::scroll-marker-group
is positioned to the right, we can confidently say that scroll-marker-group: after
is correct assuming that the writing mode is left-to-right.
Browser support
We can detect browser support for it, if needed:
@supports selector(::scroll-marker-group) {
/* ::scroll-marker-group supported */
}
@supports not selector(::scroll-marker-group) {
/* ::scroll-marker-group not supported */
}
The same thing in JavaScript:
if (CSS.supports("selector(::scroll-marker-group)")) {
/* ::scroll-marker-group supported */
}
if (!CSS.supports("selector(::scroll-marker-group)")) {
/* ::scroll-marker-group not supported */
}
Specification
The ::scroll-marker-group
pseudo-element is defined in the CSS Overflow Module Level 5 specification, which is currently in Working Draft status. This means that the information can change between now and the time when it becomes adopted as a formal Candidate Recommendation for browsers to implement.