It can be difficult for web developers to guarantee a well-controlled scrolling experience, but luckily a CSS module entitled “Scroll Snap” promises to help. It will enforce where a scroll position ends after a scrolling operation has completed.
Amongst other things, this module contains features to control facets such as panning, combined with “snap positions”, and produces a particular alignment of content within a scrolling container.
The W3C recently released Scroll Snap as a Candidate Recommendation that includes well-thought out implementations and examples along with updated syntax. Let’s dive in.
Scroll Snapping Terminology
To fully understand the power of scroll snapping and how it works, we need to understand its terminology. Doing so will also help avoid confusion when these new terms are used throughout this tutorial.
Scroll snap takes place within a “snapport” or “scrollport”; however, both mean the same, and can also be referenced as a “scroll container”. This is the region where your scroll snapping behavior resides as indicated in the diagram above (outer dashed border). The intentions are to help enforce the scroll positions that a scroll container’s scrollport will end at after a scrolling operation has completed.
Each item of this “snapport” is referred to as a “snap area”, and is the object(s) you’ll be targeting. Each snap area contains a “snap position” also defined by the “snap position” of the scroll container and represented by the red dotted line in the diagram above.
With the terminology out of the way let’s review some examples and explore how this functionality works in real life. If you’d like to read more about other types of use cases you can start with this W3C example using a photo gallery as its demonstration case, and here as well. There’s also an interesting update from the Modules August 2017 CR specification which states some intriguing behavior that
:target should possess.
Scroll Snap Demos
At the time of this writing it’s best to view the following demos with Safari 11 as other browsers (while noted to support) don’t actually have full support with the new syntax, in spite of data from caniuse and personal testing.
The example below showcases only the very minimal properties required to initiate the CSS Scroll Snap behavior and doesn’t include any polyfills as I was unable to find a working polyfill that functioned with the most recently published syntax. It’s also good to note that any scroll container will require another familiar CSS property defined known as
The demo above takes advantage of the y-axis as the snap position however, you could do it just as easily in the x-axis. If you don’t have Safari 11 on your system here’s a screen recording showing the live demo functionality provided above.
The panels snap neatly. Notice as I scroll there is a point where the scroll momentum takes over and advances to the next box. Pretty snappy huh?
Here’s a second demo showcasing the y-axis to display imagery in a gallery-esque fashion.
As the user scrolls horizontally, the momentum lands dead center of the scrollport and snap area region regardless of the image size.
Scroll Snap Properties and Syntax
Now it’s time to review and explain the actual properties with regards to their syntax and accepted values.
The current Scroll Snap specification contains only four properties and each one plays an important role. Those four properties are…
Let’s take a closer look and explain what each one does, where it is defined, and what kinds of values are accepted.
This property specifies whether a scroll container is in fact a “scroll snap container” or “snapport”, how strictly it snaps, and which axes are used. If no strictness value is specified, the
proximity value is passed as the default. This property also accepts another value that assists in defining the “snap axis”. This would allow you to pass in two values of your choosing (i.e.
scroll-snap-type: y mandatory). In this case, we’re stating the
snap-type only occurs in the y-axis and is
Scroll Snap Axis:
x: The scroll container snaps to snap positions in its horizontal axis only.
y: The scroll container snaps to snap positions in its vertical axis only.
block: The scroll container snaps to snap positions in its block axis only.
inline: The scroll container snaps to snap positions in its inline axis only.
both: The scroll container snaps to snap positions in both of its axes independently (potentially snapping to different elements in each axis).
Scroll Snap Strictness:
none: If specified on a scroll container, the scroll container must not snap.
proximity: If specified on a scroll container, the scroll container is required to be snapped to a snap position when there are no active scrolling operations. If a reachable snap position exists then the scroll container must snap at the termination of a scroll (if none exist then no snapping occurs).
mandatory: If specified on a scroll container, the scroll container may snap to a snap position at the termination of a scroll.
The scroll-snap-align property specifies a scroll container’s snap position as an alignment of its snap area (as the alignment subject) within its snap container’s snapport (as the alignment container). The two values specify the snapping alignment in the inline axis and block axis, respectively. If only one value is specified, the second value defaults to the same value. Values accepted are
In short, this property is defined for the subsequent children of the scroll container and accepts two values. The first value represents the x-axis while the seconds represents the y-axis; for example…
scroll-snap-align: start center.
none: This box does not define a snap position in the specified axis.
start: Start alignment of this box’s scroll snap area within the scroll container’s snapport is a snap position in the specified axis.
end: End alignment of this box’s scroll snap area within the scroll container’s snapport is a snap position in the specified axis.
center: Center alignment of this box’s scroll snap area within the scroll container’s snapport is a snap position in the specified axis.
The scroll-padding values act as offsets, when declared, for a scroll container and reduce the scrollable region that is considered “viewable.” This has no effect on layout, scroll origin, initial position, and if an element is considered actually visible. There are two forms, much like the standard padding property in CSS, however there is also a longhand version such as
scroll-padding-bottom, for example.
These values represent outsets when declared for a scroll container defining the scroll snap area used for snapping items to the snapport. It works and acts the same as the
margin property including the shorthand and longhand variations such as
Due to recent updates published to the current editor’s draft you will find a lack of support across the board and no polyfill as I mentioned. There’s also a chance that the property
scroll-snap-stop is at-risk, and could be dropped during the CR period. I also discovered during my research and experimentation that
min-height doesn’t work when defined on the scroll snapping container at this time. There could be other properties that have the same results, and if you find these please leave them in the comments below.
So, that is CSS Scroll snapping from a high overview. Is it worth it? Would you find it useful? Or should it be placed in the dark corners of the universe never to be found again? Leave your comments below and, as always, happy coding!