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 :target-current
CSS pseudo-class selects active scroll markers, meaning it’s only valid when used with the ::scroll-marker
pseudo-element, like this:
/* All scroll markers */
::scroll-marker {
content: "";
border: 1px solid black;
}
/* All active scroll markers */
::scroll-marker:target-current {
background: black;
}
Scroll markers give users an extra way to navigate overflow content, making them perfect for carousels, tabs, layouts with scroll-snapping functionality, and various other scroll-based components. They’re also completely accessible right out of the box — they can be navigated using a keyboard or assistive technology, and screen readers describe them fairly well too.
Here’s a carousel example:
Syntax
:target-current {
/* ... */
}
Basic usage
To select all active scroll markers:
::scroll-marker:target-current {
background: black;
}
Although, because :target-current
only applies to scroll markers anyway, the following snippet would be less redundant:
:target-current {
background: black;
}
However, to actually create scroll markers, there are a few requirements. First, the scroll targets must exist within a scroll container whose overflow
property is set to anything other than visible
. Second, its scroll-marker-group
property must be set to either before
or after
. And finally, the scroll markers must have valid content
properties. While not a fully-functional example, here’s what these requirements (along with :target-current
) look like:
<ul class="scroll-container">
<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>
</ul>
.scroll-container {
overflow-x: hidden; /* Anything but visible */
scroll-marker-group: after; /* before | after */
.scroll-target::scroll-marker {
content: ""; /* Any valid value */
}
.scroll-target::scroll-marker:target-current {
/* Active scroll marker styles */
}
}
Example: Carousel
To better understand how scroll markers work overall, take a look at the carousel demo below. You’ll see that scroll-marker-group
is set to after
— this is because the scroll markers appear after the content visually, and therefore should do so in the tab order as well. We then select the ::scroll-marker-group
pseudo-element, using anchor positioning to position the (group of) scroll markers relative to the scroll container, as well as flexbox to organize the scroll markers within. After that, it’s simply a matter of styling the scroll markers by selecting ::scroll-marker
and styling the active scroll marker with :target-current
.
<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;
}
}
Examples: Pagination and tabs
By leveraging the capabilities of the content
property, we can give the scroll markers some content. The scroll markers in the example above don’t have any content — they’re purely visual and so the content
property is left blank (content: ""
), but the example below makes use of the counter()
function to create what’s essentially a paginated scroll container where the scroll markers are numbered and the active scroll marker is emboldened (they also appear underlined because browsers, by default, style them as links).
Here’s a similar example with tabs, where the scroll markers have worded labels and the active scroll marker has a border-bottom
:
Browser support
We can detect browser support for it, if needed:
@supports selector(:target-current) {
/* :target-current supported */
}
@supports not selector(:target-current) {
/* :target-current not supported */
}
The same thing in JavaScript:
if (CSS.supports("selector(:target-current)")) {
/* :target-current supported */
}
if (!CSS.supports("selector(:target-current)")) {
/* :target-current not supported */
}
Specification
The :target-current
pseudo-class 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.