94: CSS Carousels

๐ **Source:** [94: CSS Carousels](https://www.youtube.com/watch?v=btIOhb6AiOc)
> [!note]+ Document Notes
> tags: [css-carousels, scroll-markers, scroll-buttons, scroll-target-group, anchor-positioning]
> author: Chrome for Developers
> source: Chrome for Developers (YouTube)
> reference: https://www.youtube.com/watch?v=btIOhb6AiOc
> date created: 2026-09-29 10:34
>
> > [!info] Generated analysis โ not the author's words. Sections below are machine-written
> > from the captured source. Only text inside `> [!quote]` blocks is verbatim from the author.
> > Do not quote or attribute any other line to the named author.
>
> # ๐ท๏ธ Title: 94: CSS carousels (and scroll)
>
<!-- deep-read:sections start -->
## ๐งญ Table of contents
- [๐ Summary](#-summary)
- [๐ Main content](#-main-content)
- [๐๏ธ Notes](#๏ธ-notes)
- [๐ References](#-references)
- [๐ฃ๏ธ Paraphrase](#๏ธ-paraphrase)
- [๐ฐ Newsletter](#-newsletter)
- [โ
Action items](#-action-items)
- [๐งช Hypotheses](#-hypotheses)
- [๐ Methodology](#-methodology)
- [โ Questions](#-questions)
- [๐ฎ Future research](#-future-research)
- [๐ก Implications](#-implications)
- [๐ง Learning styles assessment](#-learning-styles-assessment)
- [๐ Accessibility assessment](#-accessibility-assessment)
- [๐ DEIB assessment](#-deib-assessment)
- [โ
Logical validity](#-logical-validity)
- [๐ก๏ธ DARVO analysis](#๏ธ-darvo-analysis)
- [๐ฏ Conclusion](#-conclusion)
- [๐ Refactor appendix](#-refactor-appendix--94-css-carousels-and-scroll)
## ๐ Summary
- **What happened.** Chrome for Developers uploaded episode 94 of The CSS Podcast on 2026-09-28. It runs 16:36. The description says it originally aired Oct 29, 2025, so every browser-version claim below is dated to that broadcast. Co-hosts Una Kravets and Bramus Van Damme walk through the CSS features that build a carousel with no JavaScript. The auto-captions spell the hosts "Yuna" and "Bramus" and several property names as plain words ("scroll target group", "target current", "interactivity inert"). The spoken forms are mapped to the CSS names in the notes.
- **The claim.** A carousel is a scroller plus affordances. The speakers say Chrome 135 shipped `::scroll-button()`, `::scroll-marker`, `::scroll-marker-group`, `:target-current`, and `interactivity: inert`. They say `scroll-target-group` landed in Chrome 140, as did CSS counters inside the alt text of generated content.
- **The mechanism.** You start with `overflow-x: auto`, `scroll-snap-type: x mandatory` and `scrollbar-width: none`. Then you opt in to generated pseudo-elements by giving `content` a value other than `none`. The browser supplies button disabled states, marker navigation and the "current" state.
- **Why it matters.** Prev/next buttons, dot indicators and active-state styling are usually JavaScript. The speakers show them as declarative CSS, including a scroll spy in two lines.
- **Key stakeholders.** Una Kravets and Bramus Van Damme (Chrome DevRel), Adam Argyle (credited for the demo gallery and configurator), front-end developers who maintain carousel JavaScript, and assistive-technology users who depend on the generated semantics.
- **Risks and tradeoffs.** Browser support is a speaker claim tied to Chrome versions and isn't verified here. Pseudo-element buttons and markers limit styling (the hosts say so at 00:07:14 and 00:10:50). `scroll-target-group` markers lack the tablist semantics that `scroll-marker-group` gives you automatically (00:11:34). The video shows no cross-browser data.
- **Bottom line.** The architecture is clear: scroll container, pseudo-element affordances, browser-managed state. Check each property's current support on MDN or caniuse before shipping, because this transcript is a year old at upload.
## ๐ Main content
**Framing.** The hosts define a carousel as a scroller. In their words, it is a set of affordances that show and hide off-screen content. They defend carousels against the "big hero carousel" reputation: some content doesn't fit a small screen, and a scroller with clear controls handles that (00:01:31).
**Feature inventory, as the speakers list it (00:01:31).** Chrome 135 brought scroll buttons, scroll markers, a pseudo-class the captions render as "target current" (`:target-current`), and inerting off-screen content with `interactivity: inert`. Chrome 140 added `scroll-target-group`. They say carousels combine well with scroll-driven animations and scroll state queries, which the previous episode covered.
**Base scroller (00:02:13 to 00:02:57).**
- `overflow-x: auto` makes a horizontal scroll container.
- `scroll-snap-type: x mandatory` on the container, with snap alignment on the children, gives a center-snapping swipe area.
- `scrollbar-width: none` hides the bar while the element stays scrollable. The speaker calls this Baseline newly available and contrasts it with `overflow: hidden`, which would block scrolling. Treat the Baseline status as a speaker claim to verify.
**Scroll buttons (00:02:57 to 00:07:14).**
- `::scroll-button()` takes a direction: `left`, `right`, `up`, `down`, the logical forms (`block-start`, `block-end`, `inline-start`, `inline-end`), or `*` to style all at once.
- The pseudo-element generates only when `content` is not `none`. The generated buttons are siblings that come before the container's children and before any scroll marker group.
- `content` accepts a visual value, then a slash, then an accessible label. The speaker's example is an arrow plus "scroll left".
- The browser sets a disabled state at the scroll limit. You can style it with the disabled pseudo-class.
- Anchor positioning places the buttons over or beside the carousel. The speakers confirm this as the easiest route.
- Limit: they are pseudo-elements, so customization is bounded.
**Scroll markers (00:07:14 to 00:10:07).**
- `scroll-marker-group: before | after` on the scroller creates the group. `before` puts it at the start of the tab order and `after` puts it after the carousel.
- `::scroll-marker` on each `li` needs `content` other than `none`, and the parent needs a non-`none` `scroll-marker-group`.
- Clicking a marker scrolls to the matching item.
- Speaker claim: in Chrome 140 or newer, CSS counter values work inside the alt-text part of `content`, so the label can read "go to item 5".
- `:target-current` matches the marker whose item is in view or snapped.
**Scroll target group and scroll spy (00:10:07 to 00:13:44).**
- `scroll-target-group: auto | none` turns existing anchor elements into scroll markers, so you get full styling. The markup must exist in the DOM.
- Differences the speaker names: `scroll-marker-group` generates the pseudo-elements and tablist semantics for you. `scroll-target-group` doesn't. Its markers behave as individual links by default, and the author controls the rest.
- Scroll spy: a table of contents `ul` with anchor links to IDs, `scroll-target-group: auto` on the list, and `:target-current` styles on the links. The speaker says it replaces more complex JavaScript.
**Resources and follow-ups (00:13:44 to 00:15:11).** The hosts point to the carousel gallery at chrome.dev/carousel (demos originally by Adam Argyle, including a video carousel that uses scroll-driven animations for a clipping effect) and a configurator that outputs copy-paste CSS. Una describes a "follow-the-leader" pattern: anchor positioning retargeted to the `:target-current` marker so an indicator tracks the active marker. Una says they plan to write about it.
**Contested or unverified in this source.** No support table, no test in Firefox or Safari, and no accessibility test results appear. Version numbers (135, 140) and the Baseline status of `scrollbar-width` come from the speakers only.
## ๐๏ธ Notes
#### โฑ๏ธ [00:00:05](https://www.youtube.com/watch?v=btIOhb6AiOc&t=5) Intro: scroll APIs that make carousels
- Una and Bramus introduce a series of scroll APIs that build custom interactive carousels on initial load with no JavaScript.
- They tie these APIs to the ones behind customizable select.
#### โฑ๏ธ [00:00:48](https://www.youtube.com/watch?v=btIOhb6AiOc&t=48) A carousel is a scroller
- Real-world examples named: app stores, music selections, product carousels, review carousels, a Belgian newspaper site.
> [!quote] [00:00:48]
> it's just a series of affordances that show and hide off-screen content.
#### โฑ๏ธ [00:01:31](https://www.youtube.com/watch?v=btIOhb6AiOc&t=91) Defending carousels and the Chrome 135 feature list
- Argument: hero carousels are a bad pattern, but small screens often have more content than space.
- Speaker claim: Chrome 135 shipped scroll buttons, scroll markers, `:target-current`, and `interactivity: inert`. `scroll-target-group` landed in Chrome 140.
- Pairs with scroll-driven animations and scroll state queries from the previous episode.
#### โฑ๏ธ [00:02:13](https://www.youtube.com/watch?v=btIOhb6AiOc&t=133) Building the base scroller
- `overflow-x: auto`, `scroll-snap-type: x mandatory`, snap alignment on children.
- `scrollbar-width: none` hides the bar and keeps scrolling. The speaker calls it Baseline newly available (verify).
- The plain scroller has no visible affordance yet, which sets up the scroll button.
#### โฑ๏ธ [00:02:57](https://www.youtube.com/watch?v=btIOhb6AiOc&t=177) `::scroll-button()` syntax and generation rules
- Directions: `left`, `right`, `up`, `down`, logical `block-start`, `block-end`, `inline-start`, `inline-end`, and `*` for all.
- Generates only when `content` is not `none`. Siblings that precede the container's children and any scroll marker group.
- Logical values ease translation to other writing modes. Physical values fit UIs that always go left and right.
#### โฑ๏ธ [00:05:04](https://www.youtube.com/watch?v=btIOhb6AiOc&t=304) Styling buttons, alt text in `content`, shared rules
- Nesting under `.carousel` with `&::scroll-button(left)` keeps rules together.
- `content` takes a visual value, a slash, and an accessible label (example: arrow, then "scroll left").
- One `::scroll-button(*)` rule, with `:focus-visible`, styles both buttons: `aspect-ratio`, `border-radius`, background.
#### โฑ๏ธ [00:06:30](https://www.youtube.com/watch?v=btIOhb6AiOc&t=390) Anchor positioning and browser-managed disabled state
- Buttons render under the carousel by default. Anchor positioning is the recommended way to place them.
- Limit acknowledged at 00:07:14: pseudo-elements restrict how far you can customize.
> [!quote] [00:06:30]
> the browser will automatically set a disabled state
#### โฑ๏ธ [00:07:14](https://www.youtube.com/watch?v=btIOhb6AiOc&t=434) `::scroll-marker` and `scroll-marker-group`
- Markers are the dot indicators. Clicking one scrolls to its item.
- `scroll-marker-group: after` on the carousel creates the group. `before` places it first in tab order.
- `::scroll-marker` on each `li` needs non-`none` content. An empty string plus a slash label works.
#### โฑ๏ธ [00:09:24](https://www.youtube.com/watch?v=btIOhb6AiOc&t=564) Counters in alt text and `:target-current`
- Speaker claim: Chrome 140 or newer lets CSS counters sit inside the alt text, so a label can read "go to item number five".
- `:target-current` selects the active marker, meaning in view or snapped. Typical styles: different color, slightly larger.
#### โฑ๏ธ [00:10:07](https://www.youtube.com/watch?v=btIOhb6AiOc&t=607) `scroll-target-group` for full styling control
- Pseudo-element markers can't be fully styled, so `scroll-target-group: auto` enhances real anchor elements.
> [!quote] [00:10:50]
> you can get around those limitations by using scroll target group auto instead.
- Values: `auto` (element is a scroll marker group) and `none`. Markup must be in the DOM. No before/after value is needed.
#### โฑ๏ธ [00:11:34](https://www.youtube.com/watch?v=btIOhb6AiOc&t=694) Semantics differences between the two group types
- `scroll-marker-group` generates pseudo-elements, navigation associations and tablist semantics automatically.
- `scroll-target-group` markers act as individual links by default. The author has full control.
#### โฑ๏ธ [00:12:18](https://www.youtube.com/watch?v=btIOhb6AiOc&t=738) Scroll spy in two lines of CSS
- Markup: `ul.table-of-contents`, `li` items with anchor links (`href="#1"`), and elements with matching IDs.
- CSS: `scroll-target-group: auto` on the list, `:target-current` styles on the active link.
- Una notes a blog post on it, linked in the show notes. Smooth scroll is optional.
> [!quote] [00:12:18]
> you can create things like scroll spy effects in just two lines of CSS now
#### โฑ๏ธ [00:13:44](https://www.youtube.com/watch?v=btIOhb6AiOc&t=824) Demo gallery, configurator, follow-the-leader
- chrome.dev/carousel has demos originally by Adam Argyle. The video demo uses scroll-driven animations for a clipping effect.
- The configurator's switches (scroll buttons, scroll marker group) output copy-paste CSS.
- Una's follow-the-leader pattern retargets an anchor to the `:target-current` marker.
#### โฑ๏ธ [00:15:11](https://www.youtube.com/watch?v=btIOhb6AiOc&t=911) Experiments and sign-off
- Una is combining scroll-driven animations and scroll state queries for more interactive carousels.
- Closing: send questions with the hashtag CSS podcast on Bluesky, and leave a review. Handles are read out and garbled in the captions.
## ๐ References
The transcript itself contains no links; the following come from the video description or are primary sources for named entities.
- [94: CSS carousels (and scroll), Chrome for Developers](https://www.youtube.com/watch?v=btIOhb6AiOc): the source video, 16:36, uploaded 2026-09-28, originally aired Oct 29, 2025.
- Carousels with CSS (https://goo.gle/46PES79): listed under Resources in the description.
- `::scroll-marker` (https://goo.gle/4mEd3o8): listed under Resources in the description.
- CSS Carousel Gallery (https://goo.gle/46Odsyp): the demo gallery at chrome.dev/carousel that the speakers name.
- Carousel Configurator (https://goo.gle/46KEir4): the copy-paste CSS generator the speakers name.
- [MDN: CSS scroll snap](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_scroll_snap): primary source for `scroll-snap-type`. Check the same site for the current status of the newer scroll-button, scroll-marker and scroll-target-group entries.
- [Baseline, web.dev](https://web.dev/baseline): the source of the Baseline label the speaker applies to `scrollbar-width`.
- Adam Argyle: credited by name for the gallery and configurator. No URL is given in the transcript.
- Bramus's scroll spy blog post: mentioned at 00:12:18 and "linked in the show notes"; the description does not include it, so find it on Bramus's site.
## ๐ฃ๏ธ Paraphrase
The hosts argue that a carousel is a scrolling box with a few controls attached, and that CSS now supplies those controls. You build the scroller first: horizontal overflow, mandatory snapping, and a hidden scrollbar that still scrolls. Then you add buttons and dot markers as pseudo-elements by giving their `content` a real value. The label after the slash in `content` becomes the accessible name, so the visual arrow and the spoken "scroll left" live on one line.
The browser does the stateful work. It disables a button at the end of the scroll range, it wires each marker to its item, and it flags the marker for the item in view so you can style it. Where pseudo-elements limit styling, `scroll-target-group: auto` lets ordinary anchors act as markers, and a table of contents becomes a scroll spy with two rules. The hosts close by pointing to a demo gallery and a configurator that emits the CSS, and Una teases a pattern where an indicator follows the active marker with anchor positioning.
## ๐ฐ Newsletter
**Your carousel JavaScript might be down to a few dozen lines of CSS.** The latest CSS Podcast episode from the Chrome team walks through the scroll APIs behind carousels. Start with a scroller (`overflow-x: auto`, `scroll-snap-type: x mandatory`, `scrollbar-width: none`). Add `::scroll-button()` for prev/next, `::scroll-marker` for dot indicators, and `:target-current` to style whichever is active. The browser handles the disabled state at each end of the scroll range, and the speakers say the same machinery drives a scroll spy in two lines.
Two cautions for theme and plugin authors. The version numbers (Chrome 135 for the basics, 140 for `scroll-target-group`) are the hosts' claims from an October 2025 broadcast, so check current support before you drop a JavaScript fallback. And the two marker approaches differ in semantics: `scroll-marker-group` gives you tablist semantics automatically, `scroll-target-group` doesn't. Test with a screen reader either way.
Links: [the episode](https://www.youtube.com/watch?v=btIOhb6AiOc), the demo gallery at chrome.dev/carousel, and the carousel configurator from the video description (https://goo.gle/46KEir4).
## โ
Action items
#### DevRel
- Developer advocacy: build a five-minute demo that converts an existing JavaScript carousel to CSS-only, and publish the before and after line counts.
- Education: run a workshop that builds the scroller, buttons and markers in three steps, with the `content` slash-label trick as the accessibility lesson.
- Developer experience: add a "carousel without JavaScript" quickstart with a support caveat that links the current browser-support data, not this episode's version numbers.
- Developer marketing: quote the mechanism (browser-managed disabled state, generated markers) and cite versions only with a support-table link.
- Community management: add a note in link-sharing channels that the episode's Chrome 135/140 claims are from October 2025 and need a support check.
- Internal/external: ask the Chrome DevRel team for the current cross-browser status of the `scroll-button`, `scroll-marker` and `scroll-target-group` features and the accessibility test notes.
#### OSPO
- Policy and governance: decide whether contributed themes may ship carousels that depend on a single-engine CSS feature without a fallback, and write the rule down.
- License compliance: check the license on chrome.dev/carousel demos before copying any code into a distributed theme or plugin.
- Security management: no direct action from this source. Nearest relevance: removing carousel JavaScript shrinks the third-party script surface.
- Software inventory: list which bundled carousel libraries in distributed themes could be retired if the CSS path is adopted.
- Developer support: publish guidance on testing generated pseudo-element buttons with keyboards and screen readers.
- Community engagement: no direct action from this source.
- Strategic alignment: set a KPI for carousel JavaScript bytes removed per release once a CSS path exists.
#### Community
- Maintainers: audit block patterns and themes for carousel JavaScript and open one tracking issue per candidate for CSS migration.
- Contributors: add a "first issue" that swaps one carousel to the CSS pattern with a progressive-enhancement wrapper.
- Sponsors: no direct action from this source.
- Ecosystem: no direct action from this source. Nearest relevance: a shared support-matrix page for new CSS features that several projects can cite.
#### WordPress
- Core: no direct action from this source. Nearest relevance: any core block with slider behavior could be evaluated against this pattern.
- Core Performance: measure the JavaScript weight of core and bundled-theme carousels against a CSS-only version.
- Core AI: none.
- **Core Program Team:** track whether carousel patterns in the block directory depend on JavaScript, as a cross-team dependency list.
- Mobile: test swipe and snap behavior of the base scroller in the mobile editor and app web views.
- Playground: build a Blueprint that loads a theme with the CSS-only carousel so people can test it in a browser tab.
- Community: no direct action from this source.
- Training: draft a lesson on scroll snap, then scroll buttons, then markers, using the episode's order.
- Marketing: none.
- Support: prepare a canned answer for "carousel buttons missing in my browser" that points to feature support.
- Design: review whether a carousel has a place in patterns, and document the affordances (buttons, dots, current state) as design-token candidates.
- Documentation: add examples-first entries for `::scroll-button()` and `::scroll-marker` with the `content` slash label shown.
- Photos: gallery-style scrolling could use the pattern. Test focus order first.
- TV: none.
- Polyglots: check that alt text inside `content` labels is translatable, since it lives in CSS rather than markup.
- Accessibility: test the generated button and marker semantics against WCAG 2.2 2.1.1, 2.4.3, 4.1.2 and 2.3.3 for any motion.
- Meta: none.
- CLI: none.
- Hosting: none.
- Tide: none.
- Openverse: image-result carousels are a candidate use. Test keyboard access first.
- Themes: pilot the CSS scroll spy on a table of contents in one theme, with a JavaScript fallback for unsupported browsers.
- Plugins: replace slider libraries in one plugin with the CSS approach behind a feature check.
#### The WPOCC
- Programs: none directly. If The WP Open Community Collective funds tooling, a support-matrix page for new CSS features is a fundable maintenance item.
- Projects: none from this source.
- Funding experiments: none from this source.
### FAIR
- Technical independence: CSS-only carousels remove a JavaScript dependency, which fits the independence goal. Record which browsers still need a fallback.
- Policies and covenants: none from this source.
- Productized governance artifacts: add a "client-side dependency" row to scorecards so removed carousel libraries show up as reductions.
## ๐งช Hypotheses
1. Replacing a JavaScript carousel with the CSS-only pattern removes at least 50% of the carousel's shipped JavaScript bytes on a typical theme.
2. The speakers' Chrome 135 and Chrome 140 version claims match Chrome's release notes for each feature.
3. `scroll-marker-group` markers pass keyboard and screen reader checks with fewer author-written ARIA attributes than `scroll-target-group` markers, because of the automatic tablist semantics.
4. A CSS scroll spy built with `scroll-target-group: auto` matches an IntersectionObserver scroll spy on active-section accuracy within one section for pages up to 20 sections.
5. Developers who use the configurator ship a working carousel faster than developers who hand-write the CSS, measured in minutes to first working build.
6. Generated `::scroll-button()` disabled states reduce carousel interaction bugs (buttons active at the end of the range) compared with hand-rolled JavaScript state.
## ๐ Methodology
- **Design for H1.** Pick 10 open-source WordPress themes with carousels. Build a CSS-only version of each. Compare gzipped JavaScript bytes per page before and after with a build report.
- **Design for H2.** For each feature, find the Chrome Platform Status entry and release notes. Record the milestone and compare it with the spoken claim.
- **Design for H3.** Build two carousels with identical content, one per marker approach. Test in Chrome with VoiceOver and NVDA, recording announced roles, names and keyboard behavior. Score against a fixed WCAG 2.2 checklist.
- **Design for H4.** Build 5 test pages with 5, 10 and 20 sections. Script scroll positions, log which link each method marks active, and compare with the section actually in view.
- **Design for H5.** Recruit 12 developers, split into two arms, and time each from blank file to a working carousel with buttons and markers. Pre-register "working" as a checklist.
- **Design for H6.** Instrument both implementations with an automated test that scrolls to each end and asserts button state. Count failures over 100 runs per browser.
- **Controls throughout.** Same content, same viewport sizes, same browser versions, and a recorded Chrome version for every test.
## โ Questions
- Which of these features are supported in Firefox and Safari today, and which are behind flags?
- What exactly does the tablist semantics of `scroll-marker-group` expose to assistive technology, and do screen readers announce the counter-based labels?
- How do the generated scroll buttons behave in right-to-left writing modes when you use physical `left` and `right` values?
- What is the fallback story when `content` alt text isn't supported? Does a button with a visual arrow and no label appear?
- Does `interactivity: inert` on off-screen slides change tab order the way authors expect, and how does it interact with find-in-page?
- How does `scroll-target-group` behave when the anchor targets aren't inside the same scroller?
- What does the configurator emit for accessibility labels by default?
- Does the scroll spy handle sections shorter than the viewport, where two headings are visible at once?
## ๐ฎ Future research
- **Cross-browser support tracking.** A single support matrix for the whole carousel feature set, updated per release, doesn't exist in this source. It would settle the version claims.
- **Assistive technology behavior.** The episode says the browser provides semantics. Independent screen reader results for generated markers would confirm or correct that.
- **Progressive enhancement patterns.** A tested pattern for falling back to plain scroll snap when pseudo-elements are unsupported.
- **Performance of scroll-driven demos.** The gallery's video carousel uses scroll-driven animations. Measurements of INP and frame timing on mid-range phones aren't shown.
- **Design guidance.** Research on when carousels help small-screen users, to back the hosts' claim that they surface content in limited space.
## ๐ก Implications
- **Practice.** The default carousel build can start from a CSS scroller plus generated affordances. JavaScript becomes the fallback, not the base.
- **Policy.** Projects that ship themes need a written rule for using features with partial browser support, including a required fallback.
- **Security.** Fewer third-party carousel scripts means fewer dependencies to patch. This is a reasoned effect, not a claim the speakers make.
- **Education.** The order in the episode (scroller, buttons, markers, current state, target group) works as a lesson sequence.
- **Funding.** Maintenance time spent on carousel libraries can move to support-matrix upkeep and accessibility testing.
- **Accessibility.** Generated names and states help only if authors supply the `content` labels. The slash-label habit is the point to teach.
## ๐ง Learning styles assessment
- **Reading level estimate.** Flesch-Kincaid Grade Level on the transcript body is about grade 8, and Flesch Reading Ease is near 65. That is an estimate from sentence and word length. CSS property names raise the effective level to an intermediate front-end audience.
#### ๐ Visual learners
- Present: the hosts describe screen visuals (demos, the configurator) but the transcript can't confirm what is on screen.
- Improve: a diagram of scroller, generated buttons, marker group and the DOM order (buttons before children) would carry the sibling-order rule better than speech.
#### ๐ Aural learners
- Present: a two-host conversation format with recaps and jokes between sections.
- Improve: read code aloud in a consistent pattern. "Colon colon scroll-button, left in parentheses" is hard to follow without seeing it.
#### ๐ฃ๏ธ Verbal learners
- Present: definitions of a carousel, a scroll spy and each property's values, plus the logical-versus-physical explanation.
- Improve: a short glossary line for "affordance" and "Baseline" would help newcomers.
#### ๐งฉ Kinesthetic learners
- Present: a stepwise build order and pointers to a gallery and a configurator.
- Improve: give a copy-paste starter in the description so viewers can try each step.
#### ๐ง Logical learners
- Present: clear conditions for generation (`content` not `none`, non-`none` group property) and a difference list between the two group types.
- Improve: a decision table for choosing `scroll-marker-group` versus `scroll-target-group`.
#### ๐งโ๐คโ๐ง Social learners
- Present: two hosts, an invitation to send CSS questions with a hashtag, and a request to share the show.
- Improve: a prompt for viewers to post their carousel builds and a community thread for support notes.
#### ๐งโโ๏ธ Solitary learners
- Present: short, self-contained, ordered by build step.
- Improve: a checkpoint after each feature: "your carousel should now show arrows."
#### ๐ฟ Naturalistic learners
- Present: no direct ties.
- Improve: the JavaScript-removal argument links to lower page weight and energy use per page view. The episode doesn't quantify it.
## ๐ Accessibility assessment
#### Screen reader semantics
- Present: the hosts stress the slash-label in `content` as the accessible name for buttons and markers (00:05:04 and 00:09:24) and note that `scroll-marker-group` supplies tablist semantics (00:11:34).
- Improve: no screen reader test is shown. WCAG 2.2 4.1.2 (Name, Role, Value) and 1.3.1 (Info and Relationships) apply to the generated controls and need verification.
#### Keyboard navigation
- Present: the group placement option (`before` puts markers first in tab order) is explained at 00:07:56.
- Improve: no walk-through of tab and arrow behavior for markers or buttons. Check 2.1.1 (Keyboard), 2.4.3 (Focus Order) and 2.4.7 (Focus Visible). The `:focus-visible` example at 00:05:04 is a good start.
#### Contrast and readability
- Present: not assessable from the transcript.
- Improve: scroll button icons and marker dots need 3:1 non-text contrast (1.4.11) against their backgrounds, and the current state should not rely on color alone (1.4.1).
#### Text resizing and reflow
- Present: the base scroller is horizontal by design.
- Improve: 1.4.10 (Reflow) allows horizontal scroll for carousels only when the content needs it. Check behavior at 400% zoom, and honor `prefers-reduced-motion` (2.3.3) for smooth scroll and scroll-driven effects in the gallery.
#### Media and captions
- Present: the video has auto-generated captions and a description with links, but no chapters.
- Improve: the auto-captions garble names and code ("Yuna", "target current", "in shadow Chrome 140", "red demos"). This is a 1.2.2 (Captions, Prerecorded) gap in substance. Code read aloud with no on-screen text fallback in the transcript is a 1.2.5 (Audio Description) concern for viewers who can't see the screen.
#### Forms and interactions
- Present: no forms. The pointer target size of the generated buttons and markers isn't discussed.
- Improve: 2.5.8 (Target Size, Minimum) requires 24 by 24 CSS pixels for the dots and buttons unless spacing exempts them. Check the defaults.
#### Standards reference
- Primary gaps against WCAG 2.2 AA: **1.2.2** (caption accuracy), **1.2.5** (visual content not described), **4.1.2** and **1.3.1** (generated semantics unverified), **1.4.11** and **2.5.8** (marker and button size and contrast unverified), and **2.3.3** (motion). The caption fix is the cheapest.
## ๐ DEIB assessment
#### Cultural breadth
- Present: examples include a Belgian newspaper site (00:00:48), and Bramus speaks from Belgium.
- Improve: no examples in right-to-left or vertical writing modes, though logical values are recommended for translation (00:03:39). A demo in Arabic or Japanese would show the point.
#### Inclusive language
- Present: plain second-person language, and the hosts explain logical properties in terms of translation and directionality.
- Improve: "Go CSS" and "Chrome 140 really hits" are idioms that may not translate. Low severity.
#### Neurodiversity support
- Present: predictable structure: define, build, add each feature, then resources.
- Improve: chapters would let viewers jump to buttons, markers or scroll spy without scrubbing.
#### Representation
- Present: two co-hosts of different backgrounds, and credit to a named third contributor (Adam Argyle).
- Improve: no outside practitioner voices, such as an accessibility specialist talking about generated semantics.
#### Psychological safety
- Present: a warm tone, thanks to contributors, and an open invitation for questions.
- Improve: the hosts say "I think a lot of people don't know this" (00:05:04). It's mild, and framing it as "worth knowing" avoids implying a deficit.
## โ
Logical validity
#### Strong reasoning
- **Definitional, 00:00:48.** Defining a carousel as a scroller with affordances gives a clear build order that the rest of the episode follows. It holds because each later feature maps to a named affordance: buttons, markers, current state.
- **Mechanistic, 00:03:39 and 00:07:56.** The generation rule (content not `none`, and for markers, a non-`none` group property on an ancestor) is stated as a precise condition. Clarify by showing the DOM and the resulting sibling order.
- **Tradeoff disclosure, 00:07:14 and 00:10:50.** The hosts name the pseudo-element customization limit, then present `scroll-target-group` as the answer. That is a coherent problem-and-solution pair.
- **Comparative, 00:11:34.** The difference list (generated pseudo-elements and tablist semantics versus link-like markers with full author control) gives readers a way to choose.
#### Fallacies
- **Unsupported support claims, 00:01:31.** "In Chrome 135, our team released a series of APIs" and the Chrome 140 claims carry no support table, and say nothing about other engines. Why weak: version numbers alone don't establish that a feature is safe to ship. Fix: link the platform status entries and a cross-browser table.
- **Hasty framing, 00:02:57.** "which is baseline newly available" states a status with no date or link. Why weak: Baseline status changes over time. Fix: cite the web.dev or MDN entry and a date.
- **Promissory claim, 00:12:18.** "scroll spy effects in just two lines of CSS now" omits the markup, the fallback, and the accessibility work. Why weak: two lines of CSS is true only if the HTML already exists. Fix: state that the HTML structure is required and that the browser must support the feature.
- **Appeal to convenience, 00:07:14.** "the browser does all this for you" sets the benefit against JavaScript without discussing behaviors you can't change. The hosts partly answer it with the pseudo-element limitation. Fix: list what stays fixed.
- **No fallacy in the tone of the credits.** Checked for ad hominem, false dichotomy and appeals to authority: none appear. Praise of Adam Argyle's work at 00:14:28 is attribution, not an argument.
#### Tone of voice
- Warm, enthusiastic and conversational, with contractions and second person ("Let's make a carousel"). Hosts trade lines, affirm each other ("Good shout") and joke about Chrome 140. The register stays instructional. Enthusiasm peaks at the scroll spy ("Go CSS", 00:13:44), where the claim is strongest and least qualified.
## ๐ก๏ธ DARVO analysis
Not applicable to this source. DARVO describes a response to accusation or criticism, and this episode is a technical walkthrough with no accuser. For completeness: **Deny.** The hosts deny nothing; they pre-empt the "carousels are bad UX" criticism at 00:01:31 by conceding that hero carousels are a poor pattern. **Attack.** No critics or competitors are attacked. **Reverse victim/offender.** No such move appears.
## ๐ฏ Conclusion
The episode's lasting idea is structural: a carousel is a scroll container with browser-generated affordances. Buttons, markers, the disabled state and the current-marker state come from CSS you declare, and `scroll-target-group` extends the same idea to a table of contents. The `content` slash-label habit is the accessibility detail worth copying first.
The support claims don't carry their own evidence. The Chrome 135 and 140 versions, the Baseline status of `scrollbar-width`, and the counter-in-alt-text feature all come from the speakers in a broadcast that aired in October 2025. No cross-browser or assistive-technology results appear.
**Next steps for readers:** check current support for each feature on MDN or caniuse before removing any JavaScript, and keep a working scroll-snap fallback. Build one carousel with `scroll-marker-group` and one with `scroll-target-group`, and test each with a keyboard and a screen reader. Then try the configurator from the description to generate a starting point.
## ๐ Refactor Appendix โ 94: CSS carousels (and scroll)
> Density: 2โ5 Literature atoms (H3 pad), 0โ3 Permanent candidates (H4 pad).
> Emitted: 4 Literature, 1 Permanent. Resonance filter applied: the follow-the-leader
> pattern and the gallery plug were dropped as unevidenced or promotional.
>
> Konik claim-header rules: present tense, declarative, โค10 words, searchable, unique.
>
> Atomicity: one declarative sentence per atom. "and"/"also" โ split.
>
> Tag pool: #bmf ยท #addendum ยท #xref ยท #articleseed ยท #storystem ยท #share ยท #aphorisms
### ๐ Literature Split Pad
#### [H1] A carousel is a scroller with affordances
> [!quote] [00:00:48]
> it's just a series of affordances that show and hide off-screen content.
**Context & use**:
- 00:00:48, Bramus answering Una's "a carousel is basically just a fancy scroll" framing.
- This definition sets the build order for the whole episode: scroller first, then buttons, markers and current state.
**Tags**: #xref #articleseed
<!-- atomicity: 1 idea โ -->
#### [H2] The browser disables scroll buttons at range ends
> [!quote] [00:06:30]
> the browser will automatically set a disabled state
**Context & use**:
- 00:06:30, right after the anchor positioning suggestion.
- Browser-managed state is the JavaScript being removed. Pair with the 00:07:14 caveat: pseudo-elements limit customization.
**Tags**: #xref
<!-- atomicity: 1 idea โ -->
#### [H3] Scroll target group escapes pseudo-element styling limits
> [!quote] [00:10:50]
> you can get around those limitations by using scroll target group auto instead.
**Context & use**:
- 00:10:50, after the hosts explain why pseudo-element markers can't be fully styled.
- Tradeoff from 00:11:34: you get styling freedom but lose the automatic tablist semantics, so accessibility work moves to the author.
**Tags**: #xref
<!-- atomicity: 1 idea โ -->
#### [H4] Scroll spy needs two lines of CSS
> [!quote] [00:12:18]
> you can create things like scroll spy effects in just two lines of CSS now
**Context & use**:
- 00:12:18, introducing the table-of-contents demo.
- The two lines assume the anchor-link markup already exists and that the browser supports the feature. Verify support before dropping an observer-based fallback.
**Tags**: #xref #share #articleseed
<!-- atomicity: 1 idea โ -->
### ๐ง Atomic Split Pad
#### [P1] Let the browser own carousel state
**Claim** (one sentence, Courtney's voice): When the platform generates a control's state and semantics, I should declare the control in CSS and reserve JavaScript for behavior the platform can't express.
**Evidence pointer**: [[#H1]] ยท [[#H2]] ยท [[#H3]]
**Scope & conditions**: Holds where the target browsers support the feature and the generated semantics pass a keyboard and screen reader test. Breaks when you need customization the pseudo-elements block, or when support is partial and no fallback exists. `scroll-target-group` moves semantic responsibility back to the author.
**Links**:
- [[Progressive enhancement for CSS features]] โ because extends
- [[JavaScript slider libraries]] โ because contrasts on where state lives โ author code versus browser
- [[WordPress theme carousels]] โ because applies-in block themes and patterns
<!-- atomicity: 1 idea โ -->
### โ๏ธ Fleeting Queue
- [F1] Confirm current cross-browser support for `::scroll-button()`, `::scroll-marker`, `scroll-marker-group` and `scroll-target-group`, since the episode's Chrome 135/140 claims date from Oct 2025 โ https://www.youtube.com/watch?v=btIOhb6AiOc #fleeting #inbox
- [F2] Find Bramus's scroll spy blog post mentioned at 00:12:18, since the description does not link it #fleeting #inbox
- [F3] Test whether counter values in `content` alt text are announced by VoiceOver and NVDA on generated markers #fleeting #inbox
- [F4] Article seed: "Two lines of CSS, plus the HTML you already needed" on how short-code claims omit prerequisites #fleeting #inbox #articleseed
- [F5] Open question: which is right for a theme, `scroll-marker-group` or `scroll-target-group`, when a screen reader user is the priority #fleeting #inbox
### โ Things 3 (max 2 actions)
- [ ] Check MDN and Chrome Platform Status for the carousel pseudo-elements and `scroll-target-group`, and record the support matrix โ research, 20 min #things
- [ ] Build one test carousel with the configurator output and run a keyboard and screen reader pass โ accessibility test #things
<!-- deep-read:sections end -->
๐ **Full text:** [[Full Document Contents/Articles/94 CSS Carousels.md|94: CSS Carousels by Chrome for Developers]]
## Highlights
- [00:00:05] [music] >> Welcome back to the CSS podcast. This season is all about the latest and greatest in the CSS and UI world, which is the most exciting space in web development right now. So, buckle up for another exciting update. I'm your co-host, Yuna. >> And my name is Bramus. >> And today's update is a bit of a big one. It's a series of scroll APIs that together let you build custom interactive carousels on initial load without any JavaScript required. And like the APIs that make up the customizable select, these APIs which make up the CSS carousel let you do even more interesting scroll-based things. [00:00:48] >> And the reason you keep bringing up scroll so much is because a carousel is basically just a fancy scroll, right? >> Yep, exactly. It might not appear like it from the outside, but when you dig into the parts of what makes a carousel, it's just a series of affordances that show and hide off-screen content. >> So, right. We we see that everywhere on the web, and not just those big hero carousels, but there's app stores or music selections or product carousels, review carousels. Like, I think even the main newspaper website in Belgium here, they also use a carousel to show the articles. >> Yeah, those are some great examples. I see them all over the web, too. I think it's important to change the way that people think immediately and respond to carousels negatively because they're thinking of this is those big hero ([View Highlight](https://read.readwise.io/read/01m3psma4rnegbjwe9p6y5jrp7))
- Note: [H1] A carousel is a scroller with affordances
- Tags: atom/literature/h1
- [00:05:47] visual on the page and then some kind of accessible fallback alt text within that same line. So, what I would do is content colon my icon {slash} scroll left. And that in parentheses, too. And that would be like the label for what's happening when you just see this arrow. And then the same thing for scroll button right, except I'd have the right arrow {slash} and then scroll right as the accessible label. And then finally, if I wanted to style both of them at the same time, I could have add colon colon scroll button with a star in the parentheses and then colon focus visible. And this would be when focus is visible on those scroll buttons, I could have like an outline, or I could just have it without focus visible, just general styling like an aspect ratio, a [00:06:30] border radius, a background. And this way, I don't have to repeat the styles for both the left and right button. I could just have it in one place cuz I'm selecting both and then applying all those styles. So, now you have scroll buttons with little icons inside of them that show left and right arrows. We have some alt text that says scroll right and scroll left. And we have some styling like a background, border radius, aspect ratio. >> Cool. But, officially, they will just right now show up underneath the carousel. So, most likely, you want to position them like on top of that carousel or maybe to left and to right of it. I'm thinking anchor positioning. >> Yes, that's a great call, and that's the easiest way to do it. This works really well with anchor positioning. And another cool thing is that the browser will automatically set a disabled state ([View Highlight](https://read.readwise.io/read/01m3psmchwdy75mn16rq624260))
- Note: [H2] The browser disables scroll buttons at range ends
- Tags: atom/literature/h2
- [00:10:07] the active scroll marker, which is the state for when the marker is in view or snapped. >> Yes, so in your CSS, if you want to style your currently active scroll marker differently, which you should, you can write a selector such as li and then colon colon scroll marker to target that specific marker, then followed by the colon target current pseudo class selector say like when this is active, I want it to be styled differently. And what you can do there is like you can give it a different color or make it a little bit bigger and so on. >> Nice, yeah. There is another new carousel feature too that I want to talk about, which just landed and it's called scroll target group in shadow Chrome 140. You know how scroll markers have their [00:10:50] limitations because they're just pseudo elements. Like we just talked about how you could have some icons in there, but you can't really have full control over styling. Well, you can get around those limitations by using scroll target group auto instead. Because this allows you to enhance existing anchor elements into scroll markers, the behavior of scroll markers, not the pseudo. So, you get full style ability. Scroll target group is a property that accepts two values, auto, which specifies that the scroll element is a scroll marker group, and none specifying that it isn't. Scroll target group will also create essentially a scroll marker group, though you don't have to set it before or after to see the scroll markers since you've already put the markup in the ([View Highlight](https://read.readwise.io/read/01m3psmes6stk5b2bp48d2gm47))
- Note: [H3] Scroll target group escapes pseudo-element styling limits
- Tags: atom/literature/h3
- [00:11:34] DOM. You have to have the markup in the DOM directly. Scroll marker groups are created using scroll target group and they behave similarly to markers created using scroll marker group, but they have some differences. Scroll marker group automatically creates a set of pseudo elements to represent the group and the scroll markers and they automatically have the expected navigation associations. The browser does this for you. A group generated with scroll marker group automatically has tabless semantics where a scroll target group does not. The markers of a group specified using scroll target group behave like individual links by default, but the author has full control over these. So, one neat thing that you can do with these more customized scroll [00:12:18] markers is that you can create things like scroll spy effects in just two lines of CSS now, which I just wrote a blog post about and I'll link in the show notes. A scroll spy is basically a visual affordance that follows a table of contents and highlights which section you're on to help you keep your place in a UI or if you're doing some kind of online workshop or if there's a lot of content. And the code looks like this. First, you need to have some markup, some HTML, where you might have like an unordered list and that might have a class of table of contents and then you have list items inside of your unordered list with links that are going to be anchor links like a href hash one and then inside of that the text be like section one. So, this is going to link with in your page. And then you might ([View Highlight](https://read.readwise.io/read/01m3psmh6ewn2qx65nz77yc2ma))
- Note: [H4] Scroll spy needs two lines of CSS
- Tags: atom/literature/h3