scroll-marker-group

Daniel Schwarz on

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 CSS property determines if the ::scroll-marker-group pseudo-element is generated within the scroll container that the property is set on, and where. When creating scroll markers, you’re required to set scroll-marker-group to either before or after, although there are other requirements, too.

Scroll markers can be used to create CSS carousels, tabs, scroll-snapping components, and other scroll-based components. While by no means a fully-functioning component, a scroll container with overflow content would look something like this:

<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 {
  scroll-marker-group: before;

  &::scroll-marker-group {
    /* ... */
  }

  .scroll-target::scroll-marker {
    /* ... */
  }
}

And then the resulting HTML (if you were to inspect it in DevTools) would look something like this:

<ul class="scroll-container">
  <::scroll-marker-group>
    <!-- Five scroll markers -->
    <::scroll-marker>
    <::scroll-marker>
    <::scroll-marker>
    <::scroll-marker>
    <::scroll-marker>
  </::scroll-marker-group>

  <!-- 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>
</ul>

If you were to click on the third scroll marker, you’d be scrolled to the third scroll target in a scroll-snapping manner, all-in-all providing users with an additional way to navigate overflow content. Scroll markers are fully accessible, too. Users can navigate them using keyboards and assistive technologies, and screen readers are also able to decipher them quite easily.

Syntax

scroll-marker-group: <position>;
  • Values: none | before | after
  • Initial: none
  • Applies to: scroll containers
  • Inherited: no
  • Computed value: as specified
  • Animation type: discrete

Values

The <position> can be one of the following values:

  • none (default): Don’t generate ::scroll-marker-group.
  • before: Generate ::scroll-marker-group at the beginning of the scroll container (has the same effect as ::before).
  • after: Generate ::scroll-marker-group at the end of the scroll container (has the same effect as ::after).

The before and after values determine the tab order of the scroll markers that get generated within ::scroll-marker-group. The before value ensures that the scroll markers come before the scroll container’s content in the tab order, and after ensures that they come after. They also determine the ::scroll-marker-group’s layout box order, but this hardly matters as you’ll likely be anchor-positioning it relative to the scroll container anyway.

Basic usage

To use scroll markers, start with a scroll container with overflow content inside (e.g., a carousel where only one slide is shown at a time and the rest are “cut off”). The overflow property must be set to anything other than visible; otherwise the ::scroll-marker-group pseudo-element simply won’t show up.

And, of course, you’ll need to set scroll-marker-group to either before or after depending on the desired tab order.

Finally, each scroll target’s ::scroll-marker must have a valid content property.

If these requirements have been met, you’ll have a fully-functional scroll container with accessible scroll markers.

<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-marker-group {
    /* ... */
  }

  .scroll-target::scroll-marker {
    content: ""; /* Any valid value */
  }
}

In the carousel example below, 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, ensuring that the tab order matches this visual order.

In addition, Flexbox is used to lay out the scroll markers.

<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

In the example below, scroll-marker-group is set to before this time, because the scroll markers (presented as tabs) appear before the scroll container’s content.

Knowing when to use before and when to use after is very clear-cut. In the example below where ::scroll-marker-group is aligned to the right, it’s still quite obvious that scroll-marker-group: after is correct (if the writing mode is left-to-right, that is).

Browser support

We can detect browser support for it, if needed:

@supports (scroll-marker-group: before) {
  /* scroll-marker-group supported */
}

@supports not (scroll-marker-group: before) {
  /* scroll-marker-group not supported */
}

The same thing in JavaScript:

if (CSS.supports("scroll-marker-group: before")) {
  /* scroll-marker-group supported */
}

if (!CSS.supports("scroll-marker-group: before")) {
  /* scroll-marker-group not supported */
}

Specification

The scroll-marker-group property 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.

More information