Unfortunately, you'll need JavaScript to change scrolling behavior when the scrolling direction changes.
π€· I'm Not 100% Sure Why It Works...
I immediately thought that:
- registering the "scroll" event to
window
- assigning
scroll-snap-type: y mandatory
to <body>
β£
- and getting a distance from
window.scrollY
π‘ to compare with.
This and many other combinations derived from here and here eluded me. Upon further digging, the CSS property, scroll-behavior
will not propigate from the <body>
to the viewport (aka window
) -- instead it's the <html>
tag that'll actually be detected when a "scroll" event is triggered. Although scroll-behavior
is for scrolling from links, it's the only clue that lead me in the right direction, and I can't find a real good explination as to why it appears that CSS scrolling depends solely on the root. I believe that since the content takes up the whole viewport, window
is the best choice to bind the event handler to and that CSS scrolling doesn't bubble the standard way.
β£<html>
π‘document.body.getBoundingClientRect().top
Details are commented in exaple below
Note: The iframe in which Stack Snippets reside within are not at all a close proximity to what the real dimaensions are. To get the true dimensions (like viewport) and associated behavior (like scrolling), review it in
Full page
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
:root {
font-family: 'Georgia';
font-size: 62.5%;
line-height: 1;
scroll-behavior: smooth;
}
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
section {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
font-size: 1.6rem;
outline: 5px dashed tomato;
scroll-snap-align: start;
}
section:nth-of-type(odd) {
color: gold;
background: navy;
}
section:nth-of-type(even) {
color: lime;
background: black;
}
h1 {
font-size: 6em;
margin: 0;
}
</style>
</head>
<body>
<section><h1>I</h1></section>
<section><h1>II</h1></section>
<section><h1>III</h1></section>
<section><h1>IV</h1></section>
<section><h1>V</h1></section>
<section><h1>VI</h1></section>
<section><h1>VII</h1></section>
<section><h1>VIII</h1></section>
<section><h1>IX</h1></section>
<section><h1>X</h1></section>
<script>
/*
Declare an initial value outside of event handler so that it is retained
after the function is done.
*/
let start = 0;
// Bind window to the scroll event
window.addEventListener('scroll', function() {
// Reference the BCR of <body>
const bcr = document.body.getBoundingClientRect();
/*
Get the distance from the top of viewport and the top of the body
*/
const stop = bcr.top;
/*
If that distance greater than start, disable scroll-snap-type on <html>
*/
if (stop > start) {
document.scrollingElement.style.setProperty('scroll-snap-type', 'none');
//console.log('up')
} else {
// Otherwise, enable scroll-snap-type
document.scrollingElement.style.setProperty('scroll-snap-type', 'y mandatory');
//console.log('down');
}
// Set start as stop for the next scroll
start = stop;
});
</script>
</body>
</html>