A carousel without a single line of JavaScript: snapping scroll by finger, trackpad and keyboard everywhere, native arrows and dots in Chrome and Edge 135+.
CSS natif0 JSscroll-marker
Updated
01
02
03
04
05
Hover or click the scene to interact
This effect is free — the Gallery category contains 44 effects total, including 6 free. Effect.Labs has 840 vanilla effects. Explore the category →
Design, planting and upkeep of private gardens within 40 km.
Request a quote
Square vegetable bedsRennes · 2026
Natural pondVitré · 2025
Wooden deckSaint-Malo · 2025
Wildflower meadowFougères · 2024
Clipped hedgeDinan · 2024
① A landscaper's projects, browsed with a finger
WhenOn the Verdaline landscaper's website, a short introduction and the "Request a quote" button sit on the left; on the right, the row of five gardens (vegetable beds, pond, deck, meadow, hedge) with name and town as a caption. On a phone, the text disappears and the row takes the full width.
WhyVisitors browse the photos as in a phone gallery, without waiting for a script. The next slide sticks out on the right edge: it's obvious there is more to swipe.
Settings--coc-max-width: none, --coc-slide-width: 80%, --coc-ratio: 4/3, one <img> per slide (SVG illustration) and an HTML caption; dots recoloured green to stay visible on the beige background (scene CSS). The scene is live: try a swipe, Shift + wheel or the arrows.
enBrumeline
Citrus MistGin, grapefruit, rosemary9% ABV€11
Velvet RedRum, raspberry, lime12% ABV€12
Cold LagoonVodka, curaçao, pineapple10% ABV€11
Dry GardenCucumber, basil, tonicalcohol-free€8
Every cocktail exists without alcohol: ask at the bar.
② A bar's cocktails, one card per dot
WhenOn the Brumeline bar's online menu, Cocktails tab: one card at a time (illustrated glass, name, ingredients, strength, price), the dots under the card to jump straight to the fourth cocktail, the arrows on each side. A line reminds that everything comes alcohol-free too.
WhyEach cocktail gets the full space for its illustration and description, and the dots act as a table of contents. In Firefox and Safari the menu stays readable by swiping.
Settings--coc-slide-width: 100% (one card per view), --coc-ratio: auto and a 180 px height set by the scene, cards on a midnight-blue background. On a narrow screen the illustration is hidden and the text keeps the room.
enTireluneNovember
Balance€2,418
Spent this month€1,163
Home
Food
Transport
Outings
Subscriptions
Tip of the day · ← → keys
Round card payments up to the next euro: the difference goes to your savings.
Your subscriptions cost €64 a month: two haven't been used in 90 days.
Set an “outings” cap: you'll be warned at 80%.
On the 1st, move savings first, spend afterwards.
③ Tip of the day in a budgeting app, by keyboard
WhenIn the Tirelune dashboard, next to the balance, the month's spending and a small chart by category, a purple "Tip of the day" box holds four short tips. Click the box (or Tab to it) and the ← → keys move from one tip to the next; the dots show where you are.
WhyIt's a small secondary detail: it must neither move by itself nor take space. Native keyboard scrolling is enough, no extra button needed.
Settings--coc-slide-width: 100%, --coc-ratio: auto with an 84 px minimum height, native arrows hidden by the scene CSS (::scroll-button { display:none }), dots kept.
How it works
Everything relies on the browser's own scrolling. The .coc-carousel row is a flex container that scrolls horizontally (overflow-x: auto) with snapping (scroll-snap-type: x mandatory): each .coc-slide is 78% of the width and stops centred. You move it with a finger, a trackpad, Shift + wheel, or ← and → when it has focus (it carries tabindex="0").
In Chrome and Edge 135 and later, the CSS adds what the browser can now generate by itself: two arrows ::scroll-button(left) / ::scroll-button(right) that scroll by one page and dim at the ends, and one ::scroll-marker dot per slide, grouped under the row (scroll-marker-group: after); the dot of the visible slide turns aqua thanks to :target-current. Firefox and Safari don't know these pseudo-elements yet: no arrows or dots, but a thin scrollbar stays visible for mouse users (it is hidden only where the dots exist, through @supports selector(::scroll-marker)).
The row takes its container's width, up to 640 px by default. Each slide accepts an <img> that covers it entirely; without one, the gradient from the --g variable shows. With no script involved, several carousels on a page are independent by nature.
Accessibility
Roles: the row is a named aria-roledescription="carousel" region, each slide a role="group" "1 of 5". Chrome reuses these names for the dots, exposed as tabs ("1 of 5, tab").
Named arrows: the alternative text of content (content: "‹" / "Previous") gives the native arrows the names "Previous" / "Next"; translate it in your CSS.
Keyboard everywhere: Tab brings focus to the row (aqua outline), then ← → scroll by one slide. In Chrome 135+, arrows and dots are reachable with Tab as well.
Reduced motion: under prefers-reduced-motion: reduce, smooth scrolling (scroll-behavior: smooth) is turned off: arrows and dots bring the slide in at once.
Touch: native scrolling, so a vertical gesture always scrolls the page and the momentum is the system's own.
Browser compatibility
Base: scroll-snap-type (Chrome 69, Firefox 99, Safari 11) and aspect-ratio (Chrome 88, Firefox 89, Safari 15). Arrows and dots: ::scroll-button, ::scroll-marker, scroll-marker-group and :target-current only exist in Chrome and Edge 135+; Firefox and Safari don't have them (@mdn/browser-compat-data 8.1.8). Measured in Chromium 151 (arrows, dots, names read out, clicking a dot), Firefox 153 and WebKit 26.5 (keyboard scrolling, no errors, full-width row in an 800 px area).
Chrome 135+✓ Full, arrows and dots (measured)
Edge 135+✓ Full (Chromium engine)
Firefox 99+✓ Snapping scroll without arrows or dots (measured)
Safari 15+✓ Snapping scroll without arrows or dots (measured in WebKit)
Mobile iOS 15+✓ Finger swipe, no dots; not checked on a device
Android Chrome 135+✓ Full, arrows and dots
Before Chrome 135 and in Firefox and Safari: a row that scrolls by finger, trackpad, Shift + wheel and keyboard, with a thin scrollbar. If your visitors mostly use a mouse without horizontal scrolling, add your own navigation links or buttons.
The code
Copy the two blocks (HTML and CSS) into your page. No JavaScript, no dependencies.
The row takes its container's width up to this limit; none for the full width.
Slide width (CSS — --coc-slide-width)
78%
100% for one slide per view; under 50% to see several.
Proportions (CSS — --coc-ratio)
16 / 9
Width/height ratio of the slides; auto if you give them a height.
Slide background (HTML — style="--g: …")
linear-gradient(135deg,#6d8bff,#5cffd8)
Gradient or colour of each slide; an <img> inside covers it.
Active dot (CSS — ::scroll-marker:target-current)
#5cffd8, scale 1.3
Colour of the visible slide's dot (Chrome / Edge 135+).
Arrow names (CSS — content: "‹" / "Previous")
"Previous" / "Next"
Text read by screen readers for the native arrows; translate it in your CSS.
FAQ
Why can't I see any arrows or dots?
You're on Firefox, Safari or a Chrome older than version 135: these browsers don't generate ::scroll-button and ::scroll-marker yet. The row stays usable by finger, trackpad, keyboard and the scrollbar.
How do I centre the first slide on load?
Snapping centres the slides, but the first one can't be centred since there's nothing on its left. Add an 11% padding-inline (half the free space) on .coc-carousel so it starts in the middle.
Can the slides scroll by themselves?
Not without JavaScript: this carousel only moves when someone scrolls it. That's also what makes it calm: no imposed animation, nothing to pause.