Scroll Snapping with CSS Snap Points
New CSS Properties
Scroll snapping allows you to define special points in the content of a scrollable container using CSS. When a user scrolls in this container, the scroll offset will come to rest at one of these special offsets. To motivate snap scrolling, consider this horizontally scrolling gallery:
Notice how scrolling can leave us at an awkward position where we see a sliver of one image and only part of the next. Let’s look at how we can use the new
scroll-snap-* properties to achieve paginated scrolling. Note that the examples shown in this post are all available in this scroll snapping gallery.
Scroll Snap Type
scroll-snap-type on the parent scrolling container is
none, which indicates that the container opts out of any scroll snapping behavior. To opt in, we set the value to be
mandatory, which guarantees that the visual viewport of the container will rest on a snap point when there are no active scrolling operations. Also note that another value for
proximity, which indicates that scrolling may come to rest on a snap point only if scrolling takes us near the snap point. Currently, WebKit only supports mandatory snapping.
Scroll Snap Points-X and -Y
scroll-snap-points-y properties determine how to place snap points along the horizontal and vertical axes of the scroll snap container, respectively. The values here are
none (the default) or
repeat(length), where a CSS
length unit indicates any type of expression indicating a length. These include raw pixel values, viewport units, percentages (relative to the container’s padding box) and even
calc() expressions. Please note that negative
repeat() values are handled as parsing errors, and any value that comes out to less than
1px is clamped to
repeat() value indicates that snap points should be placed at regular intervals along the x or y axes, respectively. Using the above two properties, here is an example of mandatory scroll snapping with horizontal snap points at every 100% of the container width using
repeat(100%). If you’re on a browser that supports scroll snapping, you can also check out Scroll Snapping Demo 1.
Each snap point is located at the top left corner of each image. Scroll snapping makes each snap point come to rest at the top left corner of the container, marked by the blue cross.
Scroll Snap Coordinate
If our images are different sizes, we won’t be able to use
repeat(), since the interval will vary from image to image. Instead, we can use
scroll-snap-coordinate on a child element to generate one or more snap points relative to each child element. This property accepts either “none” or a space-separated list of coordinates. Each coordinate is of the form
length length, representing the x and y positions of the coordinate, respectively. Just like before, each
length is generalized to match any generic length value, and percentage-based length values use the dimensions of the child element’s border-box. The following example places a snap coordinate at each child element’s top left corner, allowing us to snap to unevenly spaced elements. See Scroll Snapping Demo 2.
Scroll Snap Destination
Another way to improve the gallery would be to center each image relative to the container. Up until now, we’ve been aligning each snap point to the top left corner of the parent container. However, by changing
scroll-snap-destination, we’re able to manipulate where snap points animate to. The destination value is a single position consisting of two space-separated
lengths. Percentage-based values are computed relative to the padding box of the scroll snapping container. We use this property in conjunction with
scroll-snap-coordinate on each child element to animate each child element to the center of the container. See Scroll Snapping Demo 3.
Notice that the position of the blue cross is now in the center of the container, since we set the destination to
50% 50%. The snap points are also now in the center of each child element, so the center of each child element now comes to rest at the center of the container.
Our scroll snapping implementation supports 2D snapping as well, when scroll snap points in both axes are active or when elements are positioned in a grid-like fashion in a container. Scrolling diagonally animates the scroll offset on a curved path to its destination. See Scroll Snapping Demo 4.
We also support scroll snapping on containers to which CSS transformations have been applied. See Scroll Snapping Demo 5.
Standards Compliance and Future Work
We currently only support the most complete part of the snap points specification: 2D scroll snapping to child elements that are aligned on a grid. This means you may find more snap points than expected if your 2D scrolling container contains scroll snapping elements of uneven sizes, such as in a masonry grid layout. The CSS Scroll Snap Points specification is still a work in progress. We are considering the CSS Scroll Snapping Change Proposal. Once a consensus is reached we will either implement the alternative scrolling model, or implement the proximity type for scroll snapping, tracked by bug 135994. Since the specification is still in flux, we have prefixed our implementation with
-webkit in keeping with the W3C requirements for features that have not completed the standardization process. We intend to unprefix our scroll snapping properties once the specification approaches its final state. The spec also does not explicitly state how to handle unreachable snap points. Our current implementation clamps all x and y offsets of each snap point to the min and max scroll offsets of the scroll snapping container. Furthermore, to prevent content from being unreachable, we emit snap points at the min and max scroll offsets of the container as well. You can use scroll snapping on the nightlies, as well as Safari on OS X El Capitan and iOS 9. We hope you’ve enjoyed reading about scroll snapping, and we’re excited to see what you create with it!