This post was published 8 years ago
There's a chance things are out of date or no longer reflect my views today
Get up to speed with scroll snap points
Scroll snap points is the answer to the need for JavaScript carousels, to an extent. As browsers gain more and more new features in CSS, it’s important to keep up to date with them. As the generalisation is; where you can replace JavaScript with CSS you gain performance improvements. Carousels in my experience are a good chunk of the need for JavaScript on the average website. So I’m very interested at the prospect of using scroll snap points to replace that.
This post is out of date. Scroll snap points has been updated significantly since this post was written. Many of the properties will no longer work, until this post can be updated, I would advise referring to the official spec.
Scroll snap points is the answer to the need for JavaScript carousels, to an extent. As browsers gain more and more new features in CSS, it’s important to keep up to date with them. As the generalisation is; where you can replace JavaScript with CSS you gain performance improvements. Carousels in my experience are a good chunk of the need for JavaScript on the average website. So I’m very interested at the prospect of using scroll snap points to replace that.
Browser support
Currently browser support isn’t great (as of writing), due to Chrome not supporting scroll snap points altogether. So this cuts out a massive part of anyone’s audience. Always check caniuse for up to date usage.
Prefixes and deprecations
It’s important to note as well Safari is using the -webkit-
prefix. The properties scroll-snap-points-x
and scroll-snap-points-y
are deprecated according to MDN.
The behaviour
Scroll snap points should behave quite familiarly. If you scroll or swipe an area that has it enabled, it will snap to the next area, that has been specified in CSS.
Properties on the scroll container
There are two types of properties that are necessary for scrolling regions, those on the container and those on the child elements. Some will also have the ability to be used on both the container and child elements.
Basic CSS required
Part of making this functionality viable means a base level of CSS will be required for the scroll container.
Horizontal scroll regions
.scroll-container {
width: 100vw;
height: 100vh;
white-space: nowrap;
overflow-x: auto; }
Vertical scroll regions
.scroll-container {
width: 100vw;
height: 100vh;
overflow-y: auto; }
Defining a width
, height
and overflow
will give you a basic scrolling area to build upon with snap-points. Additionally if you want it to scroll horizontally, you will need white-space: nowrap
.
scroll-snap-type
There are 3 values for the snap type, none
, mandatory
and proximity
. none
being the more obvious value, in that if there is any snapping, it will be removed. mandatory
and proximity
allow for different types of snapping behaviour.
Comparisons
When using the values mandatory
or proximity
, I found in Safari it didn’t matter too much, but in Firefox it made a clear difference.
mandatory
definitely had the more expected snapping behaviour, whereas proximity
felt somewhat broken. proximity
allows the user to scroll more freely, mandatory
doesn’t.
Differences
Another difference is, when something happens to content, such as adding, moving, deleting or resizing. mandatory
from my understanding will find the snap point again, whereas proximity
will remain.
I imagine this will become more consistent with final implementation.
scroll-snap-points-x and scroll-snap-points-y
These properties only work in Safari, with the -webkit-
prefix. This allows you to define a distance each scroll should snap to, using the repeat()
function.
.scroll-container {
scroll-snap-points-x: repeat(100%);
scroll-snap-points-y: repeat(100%); }
The value can generally be any unit of measurement, px
, em
, or vw
, to name a few. It’s fairly straightforward, but it’s clear why it was deprecated, which I will get into shortly.
scroll-snap-destination
This is the replacement to scroll-snap-points-x
and scroll-snap-points-y
. It’s setup to be more familiar, like background-position
, as in the first value is the x
axis and the second is the y
axis.
By default the value is 0 0
, it also accepts the same position values you would expect of background-position
. This is the benefit over scroll-snap-points
, there isn’t any new syntax to learn.
So with that in mind, once you scroll it will snap to that point within the element. If you were to use 200px as a value, it would snap to the element and an additional 200px.
See the Pen scroll snap points #1 by Steve (@stevemckinney) on CodePen.
I found the behaviour to work strangely, when experimenting with it within Firefox over Safari. If you compare the difference of the demo in either browser, it will become clearer. It feels like you’re forced towards the child elements taking up the whole browser width to work effectively.
Finally, this property you can animate, whereas scroll-snap-points
can’t. That’s for a separate post to explore this capability.
Summary
- The properties mentioned are the minimum needed to get the scrolling behaviour
scroll-snap-points-x
andscroll-snap-points-y
only work in Safari and are being phased outscroll-snap-destination
is the replacement- If you want horizontal scrolling extra properties are required
- Similarly for vertical, but less is required
.scroll-container {
width: 100vw;
height: 100vh;
/* Not necessary for overflow-y */
white-space: nowrap;
/* Can be overflow-y */
overflow-x: auto;
/* Enable scroll snapping */
scroll-snap-points-x: repeat(100%);
scroll-snap-points-y: repeat(100%);
scroll-snap-destination: 0 0; }
On the elements
There are no supported properties, as of yet that are element only.
All elements
Currently, there is only one element that will apply to all elements.
scroll-snap-coordinate
This property can be applied to child elements too, it’s usage is similar to background-position
and you can also pass multiple coordinates.
.scroll-container {
scroll-snap-coordinate: 0 0, center center; }
.scroll-item {
scroll-snap-coordinate: 240px 240px; }
To be honest I don’t actually know how this property affected anything. It sounds like the behaviour is similar to scroll-snap-destination
. With it being able to be applied to child elements, I would have expected it to align to each differently if specified.
It feels like this property should clash with scroll-snap-destination
. I didn’t understand this very well, however it was only mentioned in MDN and supported in Firefox.
Final demo
This ended up being the best kind of layout for the most consistent behaviour across browsers that support this.
See the Pen scroll snap points #2 by Steve (@stevemckinney) on CodePen.
Future properties
The properties hereon are not currently available in any browser, but the intention is they are going to be part of this module. It may change, until the module is final, that’s where I’ll be keeping this up to date.
Not being able to use them in the browser, means interpreting how they will supposedly work. Which is quite difficult, so I will give a vague overview, particularly focusing on code usage.
scroll-snap-padding
This is a scroll container property. It works similarly to regular padding.
.scroll-container {
scroll-snap-padding: 12px;
scroll-snap-padding: 12px 0; }
The
scroll-snap-padding
property defines the snap alignment container, a region inset from the visual viewport of a scroll container used in calculating its snap positions. The snap alignment container is used as the alignment container when calculating valid snap positions. 1
scroll-snap-margin
This is a child element property. It works similar to the regular margin.
.scroll-container {
scroll-snap-margin: 12px;
scroll-snap-margin: 12px 0; }
The scroll-snap-margin property defines the scroll snap margin on elements within a scroll container, used in calculating snap positions for that scroll container.2
scroll-snap-align
This property applies to all elements, using values none
, start
, end
and centre
.
.scroll-container {
scroll-snap-align: centre; }
The
scroll-snap-align
property specifies how an element’s scroll snap margin should align with its ancestor scroll container’s snap alignment container. The two values specify the snapping behavior in the x and y axes, respectively. If only one value is specified, the second value defaults to the same value.3
Finishing thoughts
The difficulty in researching some of this CSS module tells me it’s going to go through some changes. Like the CSS shapes and exclusions modules, it’s just the start. There is plenty of room for expansion. Such as animation and control over how it’s interacted with. Animation appears possible in Firefox and with future properties.
You may be put off using such CSS, but without experimenting and looking at new properties. You’re not able to form an opinion and join in the future of CSS. You can also see the difficulty in interpreting some of these properties, and the behaviour not being what you may expect. This type of feedback is helpful for CSS spec writers.