Guides
Troubleshooting
The five layout rules that keep measuring reliable, and the symptoms you see when one of them is broken.
The five rules of a measured layout
The carousel derives everything from getBoundingClientRect(). These five rules are what keep those measurements meaningful — nearly every layout bug below is one of them broken.
- Leave the track's width alone and never set it to
fit-content. Its automatic width fills the viewport, and the negative margin widens it by exactly one gap — which is what lets the last slide reach the right edge. - Give slides
flex-shrink: 0— the0inflex: 0 0 …. - Space slides with
padding-leftplus a matching negativemargin-lefton the track, never a trailingpadding-right. - Keep
scale()off the viewport, the track and the slides. Scaling something inside a slide is fine. - Change the gap through
spaceBetweenrather than a media query.
Symptoms and causes
Every slide is the width of the viewport
A percentage flex-basis resolves against the track. If the track is sized by its own content, that is circular and the numbers stop meaning anything.
/* ✗ circular: the basis resolves against a track sized by its content */
.carousel__track {
display: flex;
width: fit-content;
}
/* ✓ let the track fill the viewport */
.carousel__track {
display: flex;
margin-left: -16px;
}The slides are narrower than I asked for
Without flex-shrink: 0 flexbox squeezes the row into the viewport, and the carousel measures the squeezed result rather than your intention.
/* ✗ the slides are squeezed to fit the viewport */
.carousel__slide {
flex-basis: calc(100% / 3);
}
/* ✓ they keep the width you set */
.carousel__slide {
flex: 0 0 calc(100% / 3);
}The loop drifts a little every lap
A trailing padding makes the last slide box different from the rest. The gap has to belong to every slide equally.
/* ✗ the last slide ends up different from the rest */
.carousel__slide {
padding-right: 16px;
}
/* ✓ every slide box measures the same */
.carousel__track {
margin-left: -16px;
}
.carousel__slide {
padding-left: 16px;
}The gap changes at a breakpoint and nothing happens
Sizes are watched with a ResizeObserver, and a slide's box keeps the same width when only its padding changes. Drive the gap from spaceBetween instead — see Responsive.
slideWidth and spaceBetween do not size anything
They only write --swipi-slide-width and --swipi-slide-gap onto the track. If no rule of yours reads those properties, nothing on screen changes — the CSS variables page has the stylesheet that reads them.
The drag stops mid-gesture on mobile
The browser claimed the gesture for scrolling. Give the viewport touch-action: pan-y.
There are fewer dots than slides
That is the intended behaviour: the carousel stops once the remaining slides fit the viewport, so five half-width slides give four snaps. Render dots from snapCount and they always match.
Still stuck
The playground puts every option next to a live carousel and prints the markup and the CSS your settings need, which is usually the fastest way to tell a layout problem from an option problem.
