'Can I achieve CSS scroll snapping without making non-snapping elements unreachable?

I'm trying to use scroll snapping via the CSS scroll-snap-type and scroll-snap-align properties, but no matter what I do I end up making non-snapping elements unreachable.

In the example below, for example. the paragraphs (<p>) are all reachable and even snapping just fine, but the header (<h1>) becomes unreachable because when I try to scroll up to view it, I just get snapped back down to the first paragraph beneath it.

html {
  scroll-snap-type: y mandatory;
  height: 100vh;
  overflow: scroll;
}
p {
  background: pink;
  padding: 3rem 4rem;
  scroll-snap-align: start;
}
<h1>THIS IS UNREACHABLE</h1>
<p>1.1</p>
<p>1.2</p>
<p>1.3</p>
<p>1.4</p>
<p>1.5</p>
<p>1.6</p>
<p>2.1</p>
<p>2.2</p>
<p>2.3</p>
<p>2.4</p>
<p>2.5</p>
<p>2.6</p>
<p>3.1</p>
<p>3.2</p>
<p>3.3</p>
<p>3.4</p>
<p>3.5</p>
<p>3.6</p>

My question: Is there a way to achieve CSS scroll snapping without making non-snapping elements unreachable?


further notes:

You'll probably notice that I'm using scroll-snap-type on the <html> tag rather than using a container, which is apparently more typical. That's because using a container makes things even worse, introducing multiple scrollbars and confusion over whether the container or the <body> is being scrolled. Also, for the scroll-snapping design I'm trying to achieve to function, I would need to force the container itself to snap to the top of the viewport, which just brings us back to using <body>, or, since that simply doesn't work (don't know why), <html>.



Solution 1:[1]

It's not really possible. Because the scroll snapping API wasn't meant to be used with mixed non-snapping elements. I ran into the same issue myself, hence why I ended up on your entry. One thing that helps a little is to use proximity instead of mandatory on the html element.

Obviously that yields a different scroll feel that you might be going for. And it has its own shares of issues; such as when you refresh the page it might still scroll down to the first <p> element because it happens to be close enough for the proximity value to trigger. To kind of avoid this you can unset snapping on the first and last child with pseudo selectors.

In the demo below it looks like it might work, but this is where things go from bad to really bad. Let's say you want to have some content below the <p>'s that also doesn't snap. If you resize the window, while at the very bottom you'll notice that the window jumps back up to the last registered snap point. Same thing will happen to any layout shifts such as opening and closing an accordion, or browsing on a mobile device with a shifting url bar. Not ideal.

So in terms of viability; mixing snap enabled together with non-snapping elements is a rabbit hole of despair, dont do it.

html {
  scroll-snap-type: y proximity;
  height: 100vh;
  overflow: scroll;
}
p:first-of-type {
  scroll-snap-align: unset;
}
p {
  background: pink;
  padding: 3rem 4rem;
  scroll-snap-align: start;
}
h2 { height: 150vh; }
<h1>THIS IS UNREACHABLE</h1>
<p>1.1</p>
<p>1.2</p>
<p>1.3</p>
<p>1.4</p>
<p>1.5</p>
<p>1.6</p>
<p>2.1</p>
<p>2.2</p>
<p>2.3</p>
<p>2.4</p>
<p>2.5</p>
<p>2.6</p>
<p>3.1</p>
<p>3.2</p>
<p>3.3</p>
<p>3.4</p>
<p>3.5</p>
<p>3.6</p>
<h2>content below</h2>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1