::scroll-marker
Limited availability
This feature is not Baseline because it does not work in some of the most widely-used browsers.
The ::scroll-marker
CSS pseudo-element can be generated inside any element and represents its scroll marker. A scroll marker behaves like an anchor (<a>
element) whose scroll target is its originating element — when activated, the element's nearest ancestor scroll container will scroll to it.
Syntax
::scroll-marker {
/* ... */
}
Description
A ::scroll-marker
is generated on an element when the ::scroll-marker
's content
property is set to a non-none
value, and its has an ancestor scroll container with a non-none
scroll-marker-group
property value (meaning that it will generate a ::scroll-marker-group
pseudo-element).
The ::scroll-marker-group
pseudo-element automatically contains any ::scroll-marker
pseudo-elements generated on the scroll container's decendants. This allows them to be positioned and laid out as a group, and is typically used when creating a CSS carousel, to create a scroll position indicator. The individual scroll markers can also be used to navigate to their associated content items.
Accessibility-wise, the scroll marker group and contained scroll markers are rendered with tablist
/tab
semantics. When you Tab to the group, it behaves like a single item (that is, another press of the Tab key will move past the group to the next item), and you can move between the different scroll markers using the left and right (or up and down) cursor keys.
Examples
Creating a responsive carousel layout
This demo creates a responsive, CSS-only carousel. It uses the columns
property and the ::columns
pseudo-element to create arbitary content columns that span the full width of their parent scroll container, which can be scrolled between. Each column contains multiple items of content, which can vary in number depending on the viewport width.
HTML
The HTML consists of an unordered list, with each list item containing some sample content:
<ul>
...
<li>
<h2>Item 1</h2>
</li>
...
</ul>
CSS
The list is given a fixed height
and a width
of 100vw
to make it span the full width of the viewport. An overflow-x
value of scroll
is then set so that the content will scroll horizontally, and CSS scroll snap is used to snap to each item or "page" — a scroll-snap-type
value of x mandatory
is used to make the list into a scroll snap container. Finally, a columns
value of 1
is set to force the list contents to display as a single column. A text-align
value of center
is also applied, to force the contents to align with the center of the list.
ul {
width: 100vw;
height: 300px;
padding: 10px;
overflow-x: scroll;
scroll-snap-type: x mandatory;
columns: 1;
text-align: center;
}
The list items are then styled:
- A
display
value ofinline-block
is set to force the list items to sit alongside one another and make the list scroll horizontally. - A fixed
aspect-ratio
of3/4
has been set on them, to control their sizing as the list size changes, but keep their width constant while the height of the list stays constant. - A
text-align
value ofleft
is set on them to override thetext-align: center
set on the parent container, so the item content will be left-aligned. - Every even-numbered list item is given a different background-color via
:nth-child()
, so that it is easier to see the scrolling effect.
li {
list-style-type: none;
display: inline-block;
height: 100%;
aspect-ratio: 3/4;
background-color: #eee;
border: 1px solid #ddd;
padding: 20px;
margin: 0 10px;
text-align: left;
}
li:nth-child(even) {
background-color: cyan;
}
The scroll-snap-align
property is set on the ::column
pseudo-elements — which represent the content columns generated by the columns
property — so that when scrolled, the list snaps to each complete column.
ul::column {
scroll-snap-align: center;
}
We then select the ::scroll-marker
pseudo-elements of each generated column using ul::column::scroll-marker
. The look of each one is handled by setting width
, height
, background-color
, border
, and border-radius
, but we also need to set a non-none
value for the content
property so they are actually generated.
ul::column::scroll-marker {
content: "";
width: 16px;
height: 16px;
background-color: transparent;
border: 2px solid black;
border-radius: 10px;
}
Finally, we set a solid black background on the the active scroll marker using :target-current
, so you can see the current carousel scroll position:
ul::column::scroll-marker:target-current {
background-color: black;
}
Result
See Creating CSS carousels for a full explanation of the above demo.
Specifications
Specification |
---|
CSS Overflow Module Level 5 # scroll-marker-pseudo |
Browser compatibility
See also
scroll-marker-group
::scroll-button()
::scroll-marker-group
::column
:target-current
- Creating CSS carousels
- CSS overflow module
- CSS Carousel Gallery via chrome.dev (2025)