Categories: css-tricks.com

Elastic Overflow Scrolling

A client asked if we could mimic the “rubber band” scrolling behavior on many mobile devices. I’m sure you know what I’m talking about. It’s a behavior that already exists and happens automatically in most browsers. In iOS Safari, for example, you’re allowed to scroll beyond the top or bottom edge of the viewport by a few hundred pixels, and letting go snaps the page back in place.

I had heard of some instances where someone might want to prevent the bounce from happening but no one had asked me to implement it, especially in a way that supports devices without a touch interface. I was actually a bit surprised there isn’t an existing CSS property for this. There’s the non-standard -webkit-overflow-scrolling property but that’s for a different type of “momentum” scrolling. Nor would I want to rely on a non-standard property that’s not on track to become part of the specifications.

OK, so what if we want to force this sort of rubber banding in our work? For starters, we’d need some sort of element acting as a container for content that requires scrolling. From there, we could reach for JavaScript, of course, but that involves adding scroll listeners or a combination of pointerDown, pointerUp, and pointerMove events, not to mention keeping track of positions, inertial movement, etc.

A CSS-only solution would be much more ideal.

Here is a container with a few child elements:

<div class="carousel">
  <div class="slides">
    <div class="slide">1</div>
    <div class="slide">2</div>
    <div class="slide">3</div>
    <div class="slide">4</div>
    <div class="slide">5</div>
  </div>
</div>

Let’s get some baseline styles in place, specifically to create a situation where we’re guaranteed to overflow a parent container.

/* Parent container with fixed dimensions for overflow */.carousel {
  width: 200px;
  height: 400px;
  overflow-x: hidden;
  overflow-y: auto;
}

/* Wrapper for slides, stacked in a column */.slides {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  width: 100%;
  height: fit-content;
}

/* Each slide is the full width of the carousel */.slide {
  width: 100%;
  aspect-ratio: 1;
}

Let’s start by adding some vertical margins. If your container has only one long item, add it to the top and bottom of the child element. If the container has multiple children, you’ll want to add margin to the top of the first child element and the bottom of the last child element.

.carousel > .slides > .slide:first-child {
  margin-top: 100px;
}

.carousel > .slides > .slide:last-child {
  margin-bottom: 100px;
}

Great! We can now scroll past the edges, but we need something to snap it back after the user lifts their finger or pointer. For this, we’ll need the scroll-snap-type and scroll-snap-align properties

.carousel {
  scroll-snap-type: y mandatory;
}

.carousel > .slides > .slide {
  scroll-snap-align: start;
}

.carousel > .slides > .slide:first-child {
  margin-top: 100px;
}

.carousel > .slides > .slide:last-child {
  scroll-snap-align: end;
  margin-bottom: 100px;
}

Note that the same applies to a horizontally scrolling element. For that, you’d change things up so that margin is applied to the element’s left and right edges instead of its top and bottom edges. You’ll also want to change the scroll-snap-type property’s value from y mandatory to x mandatory while you’re at it.

That’s really it! Here’s the final demo:

I know, I know. This isn’t some Earth-shattering or mind-blowing effect, but it does solve a very specific situation. And if you find yourself in that situation, now you have something in your back pocket to use.

Additional resources


Elastic Overflow Scrolling originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

hnikoloski

Share
Published by
hnikoloski

Recent Posts

Quick Hit #21

Seeing a lot more headlines decrying JavaScript and pumping up PHP. Always interesting to see…

1 day ago

CSSWG Minutes Telecon (2024-09-18)

For the past two months, all my livelihood has gone towards reading, researching, understanding, writing,…

1 day ago

Quick Hit #20

Having fun with Bramus’ new Caniuse CLI tool. This’ll save lots of trips to the…

2 days ago

Quick Hit #19

Two possible syntaxes for CSS masonry, one draft specification, and you get to share your…

2 days ago

Re-Working the CSS Almanac

Getting right to it: the CSS-Tricks Almanac got a big refresh this week! I’m guessing…

2 days ago

Clever Polypane Debugging Features I’m Loving

I’m working on a refresh of my personal website, what I’m calling the HD remaster.…

4 days ago