<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Robert Flack on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Robert Flack</name>
  </author>
  <link href="https://web.dev/authors/flackr/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/OoCXp829hcVrzCEmjzSd.jpg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Software Engineer on the Chrome team</subtitle>
  
  
  <entry>
    <title>Well-controlled scrolling with CSS Scroll Snap</title>
    <link href="https://web.dev/css-scroll-snap/"/>
    <updated>2018-07-24T00:00:00Z</updated>
    <id>https://web.dev/css-scroll-snap/</id>
    <content type="html" mode="escaped">&lt;p&gt;The &lt;a href=&quot;https://drafts.csswg.org/css-scroll-snap/&quot; rel=&quot;noopener&quot;&gt;CSS Scroll Snap&lt;/a&gt; feature allows web
developers to create well-controlled scroll experiences by declaring scroll
snapping positions. Paginated articles and image carousels are two commonly used
examples of this. CSS Scroll Snap provides an easy-to-use and consistent API for
building these popular UX patterns.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; CSS Scroll Snap &lt;a href=&quot;https://caniuse.com/css-snappoints&quot;&gt;is supported in all major browsers&lt;/a&gt;. A previous version of the specification was implemented in some browsers, and may appear in tutorials and articles. If material includes the deprecated &lt;code&gt;scroll-snap-points-x&lt;/code&gt; and &lt;code&gt;scroll-snap-points-y&lt;/code&gt; properties, it should be considered outdated. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;background&quot;&gt;Background &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#background&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;the-case-for-scroll-snapping&quot;&gt;The case for scroll snapping &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#the-case-for-scroll-snapping&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Scrolling is a popular and natural way to interact with content on the web. It
is the platform&#39;s native means of providing access to more information than is
visible on the screen at once, becoming especially vital on mobile platforms
with limited screen real estate. So it is no surprise that web authors
increasingly prefer to organize content into scrollable flat lists as opposed to
deep hierarchies.&lt;/p&gt;
&lt;p&gt;Scrolling&#39;s main drawback is its lack of precision. Rarely does a scroll end up
aligned to a paragraph or sentence. This is even more pronounced for paginated
or itemized content with meaningful boundaries when the scroll finishes at the
middle of the page or image, leaving it partially visible. These use cases
benefit from a well-controlled scrolling experience.&lt;/p&gt;
&lt;p&gt;Web developers have long relied on JavaScript-based solutions for controlling
the scroll to help address this shortcoming. However, JavaScript-based solutions
fail to provide a full fidelity solution due to lack of scroll
customization primitives or access to composited scrolling. CSS Scroll Snap
ensures a fast, high fidelity, and easy-to-use solution that works
consistently across browsers.&lt;/p&gt;
&lt;p&gt;CSS Scroll Snap allows web authors to mark each scroll container with boundaries
for scroll operations at which to finish. Browsers then choose the most
appropriate end position depending on the particulars of the scroll operation,
scroll container&#39;s layout and visibility, and details of the snap positions,
then smoothly animate to it. Going back to our earlier example, as the user
finishes scrolling the carousel, its visible image snaps into place. No scroll
adjustments needed by JavaScript.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Example of using css scroll snap with an image carousel.&quot; decoding=&quot;async&quot; height=&quot;356&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/b2Zbw03FzAth5NvBM2Cb.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Example of using css scroll snap with an image carousel.
    Here scroll snapping ensures at the end of scrolling an image horizontal
    center is aligned with the horizontal center of the scroll container.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;css-scroll-snap&quot;&gt;CSS Scroll Snap &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#css-scroll-snap&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Scroll snapping is the act of adjusting the scroll offset of a scroll container
to be at a preferred &lt;strong&gt;snap position&lt;/strong&gt; once the scroll operation finishes.&lt;/p&gt;
&lt;p&gt;A scroll container may be opted into scroll snapping by using the
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/scroll-snap-type&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;scroll-snap-type&lt;/code&gt;&lt;/a&gt;
property. This tells the browser that it should consider snapping this scroll
container to the snap positions produced by its descendants.  &lt;code&gt;scroll-snap-type&lt;/code&gt;
determines the axis on which scrolling occurs: &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, or &lt;code&gt;both&lt;/code&gt;, and the
snapping strictness: &lt;code&gt;mandatory&lt;/code&gt;, &lt;code&gt;proximity&lt;/code&gt;. More on these later.&lt;/p&gt;
&lt;p&gt;A snap position can be produced by declaring a desired alignment on an element.
This position is the scroll offset at which the nearest ancestor scroll
container and the element are aligned as specified for the given axis. The
following alignments are possible on each axis: &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;end&lt;/code&gt;, &lt;code&gt;center&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;start&lt;/code&gt; alignment means that the scroll container snapport start edge should
be flushed with the element snap area start edge. Similarly, the &lt;code&gt;end&lt;/code&gt; and
&lt;code&gt;center&lt;/code&gt; alignments mean that the scroll container snapport end edge or center
should be flushed with the element snap area end edge or center.&lt;/p&gt;
&lt;aside class=&quot;aside flow color-secondary-box-text bg-secondary-box-bg&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Highlighter pen&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M10.22 9.49l-5.91 6c-.77.8-.7 2.05.08 2.85L.77 22h5.68l.74-.75c.78.81 1.95.86 2.73.05l5.96-6.05-5.66-5.76zm12.46-4l-2.82-2.87c-.78-.8-2.07-.84-2.84-.04l-5.75 5.85 5.66 5.75 5.69-5.78c.77-.81.83-2.11.06-2.91z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Key Term&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; The &lt;a href=&quot;https://drafts.csswg.org/css-scroll-snap/#scroll-padding&quot;&gt;snapport&lt;/a&gt; is the area of the scroll container to which the snap areas are aligned. By default, it is the same as the visual viewport of the scroll container, but it can be adjusted using the &lt;code&gt;scroll-padding&lt;/code&gt; property. &lt;/div&gt;&lt;/aside&gt;
&lt;figure&gt;
    &lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/U9rWoMBMwhKMo6dJZE8v.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
  &lt;figcaption&gt;
    Example of a various alignments on horizontal scrolling axis.
 &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The following examples illustrate how to use these concepts.&lt;/p&gt;
&lt;h3 id=&quot;example-a-horizontal-gallery&quot;&gt;Example: A horizontal gallery &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#example-a-horizontal-gallery&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A common use case for scroll snapping is an image carousel. For example, to
create a horizontal image carousel that snaps to each image as you scroll, we
can specify the scroll container to have a mandatory &lt;code&gt;scroll-snap-type&lt;/code&gt;
on the horizontal axis.
set each image to &lt;code&gt;scroll-snap-align: center&lt;/code&gt; to ensure that
the snapping centers the image within the carousel.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;#gallery&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;scroll-snap-type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; x mandatory&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow-x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; scroll&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;#gallery img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;scroll-snap-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;gallery&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cat.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;dog.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;another_cute_animal.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Because snap positions are associated with an element, the snapping algorithm
can be smart about when and how it snaps given the element and the scroll
container size. For example, consider the case where one image is larger than
the carousel. A naïve snapping algorithm may prevent the user from panning
around to see the full image. But the
&lt;a href=&quot;https://drafts.csswg.org/css-scroll-snap/#snap-overflow&quot; rel=&quot;noopener&quot;&gt;specification&lt;/a&gt;
requires implementations to detect this case and allow the user to freely scroll
around within that image only snapping at its edges.&lt;/p&gt;
&lt;figure&gt;
  &lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/yKrUtFVhZLR9ekaws8o3.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
  &lt;figcaption&gt;
    &lt;a href=&quot;https://snap.glitch.me/carousel.html&quot; target=&quot;_blank&quot;&gt;View demo&lt;/a&gt; |
    &lt;a href=&quot;https://glitch.com/edit/#!/snap?path=carousel.html:1:0&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;example-a-journeyed-product-page&quot;&gt;Example: a journeyed product page &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#example-a-journeyed-product-page&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another common case that can benefit from scroll snapping are pages with
multiple logical sections to vertically scroll through, for example, a typical
product page. &lt;code&gt;scroll-snap-type: y proximity;&lt;/code&gt; is a more natural fit for cases
like this. It does not interfere when a user scrolls to the middle of a particular
section but also snaps and brings attention to a new section when they scroll
close enough.&lt;/p&gt;
&lt;p&gt;Here is how this can be achieved:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;scroll-snap-type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; y proximity&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Reserve space for header plus some extra space for sneak peeking. */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;scroll-padding-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 15vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;overflow-y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; scroll&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;section&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Snap align start. */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;scroll-snap-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fixed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; Header &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; Section One &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; Section Two &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; Section Three &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;scroll-padding-and-margin&quot;&gt;Scroll padding and margin &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#scroll-padding-and-margin&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The product page has a fixed position top header. The design also asked for some
of the top section to remain visible when the scroll container is snapped in order
to provide a design cue to users about the content above.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/scroll-padding&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;scroll-padding&lt;/code&gt;&lt;/a&gt;
property is a new css property that can be used to adjust the effective
viewable region of the scroll container, or snapport, which
is used when calculating scroll snap alignments. The property defines an inset
against the scroll container&#39;s padding box. In our example, &lt;code&gt;15vh&lt;/code&gt; additional inset
was added to the top, which instructs the browser to consider a lower position,
&lt;code&gt;15vh&lt;/code&gt; below the top edge of the scroll container, as its vertical start edge for
scroll snapping. When snapping, the start edge of the snap target element will
become flushed with this new position, thus leaving space above.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/scroll-padding&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;scroll-margin&lt;/code&gt;&lt;/a&gt;
property defines the outset amount used to adjust the snap target
effective box similar to how &lt;code&gt;scroll-padding&lt;/code&gt; functions on the snap scroll
container.&lt;/p&gt;
&lt;p&gt;You may have noticed that these two properties do not have the word &amp;quot;&lt;code&gt;snap&lt;/code&gt;&amp;quot; in
them. This is intentional as they actually modify the box for all relevant
scroll operations and are not just scroll snapping. For example, Chrome takes
them into account when calculating page size for paging scroll operations such
as PageDown and PageUp, and also when calculating scroll amount for the
&lt;code&gt;Element.scrollIntoView()&lt;/code&gt; operation.&lt;/p&gt;
&lt;figure&gt;
&lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/vJ4o1a537JsKzgkiAVd6.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
  &lt;figcaption&gt;
    &lt;a href=&quot;https://snap.glitch.me/product.html&quot; target=&quot;_blank&quot;&gt;View demo&lt;/a&gt; |
    &lt;a href=&quot;https://glitch.com/edit/#!/snap?path=product.html:1:0&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;interaction-with-other-scrolling-apis&quot;&gt;Interaction with other scrolling APIs &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#interaction-with-other-scrolling-apis&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;dom-scrolling-api&quot;&gt;DOM Scrolling API &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#dom-scrolling-api&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Scroll snapping happens &lt;strong&gt;after&lt;/strong&gt; all scroll operations including those
initiated by script. When you are using APIs like &lt;code&gt;Element.scrollTo&lt;/code&gt;, the
browser will calculate the intended scroll position of the operation, then apply
appropriate snapping logic to find the final snapped location. Thus, there is
no need for user script to do any manual calculations for snapping.&lt;/p&gt;
&lt;h3 id=&quot;smooth-scrolling&quot;&gt;Smooth scrolling &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#smooth-scrolling&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Smooth scrolling controls the behavior of a programmatic scroll operation while
scroll snap determines its destination. Since they control orthogonal aspects of
scrolling, they can be used together and complement each other.&lt;/p&gt;
&lt;h3 id=&quot;overscroll-behavior&quot;&gt;Overscroll behavior &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#overscroll-behavior&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.chrome.com/blog/overscroll-behavior/&quot; rel=&quot;noopener&quot;&gt;Overscroll behavior API&lt;/a&gt; controls how
scroll is chained across multiple elements and it is not affected by scroll
snap.&lt;/p&gt;
&lt;h2 id=&quot;caveats-and-best-practices&quot;&gt;Caveats and best practices &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#caveats-and-best-practices&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Avoid using mandatory snapping when target elements are widely spaced apart.
This can cause content in between the snap positions to become inaccessible.&lt;/p&gt;
&lt;p&gt;In many cases scroll-snapping can be added as an enhancement
without needing to feature detect.
If required, use &lt;code&gt;@supports&lt;/code&gt; or &lt;code&gt;CSS.supports&lt;/code&gt; to detect support for CSS Scroll Snap.
Avoid using &lt;code&gt;scroll-snap-type&lt;/code&gt; which is also present in the deprecated specification.&lt;/p&gt;
&lt;h3 id=&quot;feature-detection-in-css&quot;&gt;Feature detection in CSS &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#feature-detection-in-css&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@supports&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;scroll-snap-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token selector&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;scroll-snap-type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; y proximity&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;scroll-padding-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 15vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;overflow-y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; scroll&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;feature-detection-in-javascript&quot;&gt;Feature detection in JavaScript &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#feature-detection-in-javascript&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;supports&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;scroll-snap-align: start&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// use css scroll snap&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// use fallback&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Do not assume that programmatically scrolling APIs such as &lt;code&gt;Element.scrollTo&lt;/code&gt;
always finish at the requested scroll offset. Scroll snapping may adjust the
scroll offset after programmatic scrolling is complete. Note that this was not a
good assumption even before scroll snap since scrolling may have been
interrupted for other reasons, but it is especially the case with scroll
snapping.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; There is an &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/1562#issuecomment-389586317&quot;&gt; upcoming proposal&lt;/a&gt; to change various scrolling APIs to return a promise. This promise is resolved when the user agent either completes or aborts that scrolling operation. Once this is standardized and implemented, it provides an ergonomic and efficient way for following up a user script initiated scroll with other actions. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;future-work&quot;&gt;Future work &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-scroll-snap/#future-work&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Scroll experience was the focus of
&lt;a href=&quot;https://web.dev/2021-scroll-survey-report/&quot;&gt;a recent survey by the Chrome team&lt;/a&gt;.
The survey results identified several areas that need additional work
to shrink the gap between plugin libraries and CSS.
Upcoming work will focus on &lt;code&gt;scroll-snap&lt;/code&gt;, including:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;API availability and compatibility across browsers.&lt;/li&gt;
&lt;li&gt;Work on
&lt;a href=&quot;https://github.com/argyleink/ScrollSnapExplainers&quot; rel=&quot;noopener&quot;&gt;new CSS APIs&lt;/a&gt; like &lt;code&gt;scroll-start&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Work on
&lt;a href=&quot;https://github.com/argyleink/ScrollSnapExplainers&quot; rel=&quot;noopener&quot;&gt;new JS events&lt;/a&gt; like &lt;code&gt;snapChanged()&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
</content>
    <author>
      <name>Robert Flack</name>
    </author><author>
      <name>Majid Valipour</name>
    </author>
  </entry>
</feed>
