demo · v135

CSS-only carousel: ::column snap + ::scroll-marker dots

Both ::column and ::scroll-marker shipped in Chrome 135, and they compose. ::column { scroll-snap-align: start } turns each multi-column fragment into a snap target; ::scroll-marker on each card generates a dot row with the active slide highlighted automatically via :target-current — no JavaScript, no wrapper divs, no bookkeeping.

::column: ? ::scroll-marker: ?

the complete CSS

.carousel {
  columns: 1;              /* one card = one column */
  column-fill: auto;
  height: 260px;           /* fixed height so multicol fragments horizontally */
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
}

/* ::column — Chrome 135+: each generated fragment is a snap target */
.carousel::column {
  scroll-snap-align: start;
}

/* ::scroll-marker-group — Chrome 135+: the dot container */
.carousel::scroll-marker-group {
  display: flex;
  gap: 8px;
  justify-content: center;
  padding: 12px 0;
}

/* ::scroll-marker — Chrome 135+: one dot per card */
.card::scroll-marker {
  content: "";
  width: 10px;
  height: 10px;
  border: 2px solid black;
  background: white;
}
.card::scroll-marker:target-current {
  background: black;    /* active dot */
}

see also