How to Override the CSS Scroll Behavior with Scrollto in JavaScript

How to override the CSS scroll behavior with scrollTo in JavaScript

You can set the inline style of your container's scroll to auto, then reverting the change by altering the value of html.style.scrollBehavior before and after scrolling programmatically. JS's ScrollToOptions's behavior key-value pair cannot override CSS's scroll-behavior. The CSSOM draft mentions this:

If the user agent honors the scroll-behavior property and one of the following are true:

• behavior is "auto" and element is not null and its computed value of
the scroll-behavior property is smooth

• behavior is smooth

...then perform a smooth scroll of box to position. Otherwise, perform an instant scroll of box to position.

Your user agent honors the scroll-behavior property; this means that we're going to check one of the two conditions. When you're using window.scroll({..., behavior: 'auto'}), we're entering the first condition. The behavior we're setting is indeed auto, element is indeed not null, and the computed value of scroll-behavior property is indeed smooth. Therefore, a smooth scroll will happen. To make the condition false, we can override the computed value of the scroll-behavior property to auto by using an inline style.

Here's a simple example. Scroll programmatically without smooth behavior by clicking the Scroll down 200 button. Scroll smoothly by clicking the links.

function scrollNoSmooth() {  // Setting inline style of scroll-behavior to 'auto' temporarily  html.style.scrollBehavior = 'auto'    // This 'behavior' cannot override the CSS 'scroll-behavior'  // Do scroll  window.scroll({    top: window.scrollY + 200,    left: 0,    // behavior: 'smooth'  })    // Reverting inline style to empty  html.style.scrollBehavior = ''}
const html = document.querySelector('html')const fixed = document.querySelector('.fixed')
fixed.addEventListener('click', scrollNoSmooth)
html {  scroll-behavior: smooth;  position: relative;}
a { display: block; height: 400px; width: 100%; display: flex; justify-content: center; align-items: center;}
.fixed { display: flex; justify-content: center; align-items: center; position: fixed; width: 150px; height: 50px; border-radius: 5px; background: #121212; color: white; cursor: pointer;}
<div class="fixed">Scroll down 200</div><a name="A" href="#B">A</a><a name="B" href="#C">B</a><a name="C" href="#A">C</a>

How to override scroll functions in a window?

The window.scroll, window.scrollTo and window.scrollBy methods do not refer to the native scrolling functionality. They are used to scroll to specific locations on the webpage. If you want to implement a completly custom scrolling functionality/behaviour you need to listen to the wheel event, prevent the default and define your custom behaviour.

Note: changed scroll to wheel event as comment mentioned error

document.addEventListener("wheel", (event) => {
event.preventDefault();
event.stopPropagation();
// now define custom functionality
}, { passive: false });

Instead of window you can also apply it to any other element on the page that has a scrollbar and therefore being scrollable.

Futhermore the wheel event has values for deltaX and deltaY so you can see how much would have been scrolled since the last scroll and you can use the properties x and y to see how much had been scrolled since the beginning.

I have the scroll behavior set to smooth in CSS but how to write it in JS?

scroll-behavior CSS property make the contents within an element scroll smoothly.
While Element.scrollIntoView is used to programmatically scroll to an element.

If you want for example scroll to the header of the page with scroll-behavior: smooth you can opt-in the behavior option and set it to smooth.

var header = document.getElementById("header")
header.scrollIntoView({ behavior: "smooth" })

Scroll instantly to the top when smooth is set with CSS

This is because you have set the css property scroll-behavior to smooth.

The window.scrollTo behavior option doens't override the css value.


Replace

window.scrollTo({ top: 0, behavior: 'auto' });

With

document.documentElement.style = "scroll-behavior: auto";
document.documentElement.scrollTo({ top: 0, behavior: 'auto' }); // or just leave it window.scrollTo(...), doens't matter. I just like it this way ;)

let button = document.getElementById("test");
button.addEventListener('click', () => { // Reset the CSS scroll-behavior property document.documentElement.style = "scroll-behavior: auto"; document.documentElement.scrollTo({ top: 0, behavior: 'auto' }); // or just leave it window.scrollTo(...), doens't matter // Do more stuff here, like setting the 'scroll-behavior' back to smooth .....});
html {  height: 100000px;    scroll-behavior: smooth;}
button { position: fixed;}
<button id="test">Scroll down then click me</button>

CSS overflow-y: scroll overwrite my code and other functions not working

What is happening here?

Since your animation works with window.innerHeight whenever you try to add overflow: scroll to your container it will disable the window scrolling, in order to have only one active scrollbar at the same time (This is not actually happening but it is the problem(ish)). So the calculation of document.body.scrollHeight - window.innerHeight; will be 0 then your header animation wont fill ever due to this equation var percentage = scrollPosition / scrollableHeight * 100; (the scrollableHeight is zero so the result will be infinity).

How to fix it?

So the best way to fix this issue is to determine the active scrollbar and assign scroll-behaviour to it's parent. Since in normal flow your active scrollbar is depended on body itself you should remove overflow-y: scroll; from your container and then add scroll-behavior: smooth; to the active scrollbar parent

So your final output should be something like this:

html,body {
scroll-behavior: smooth;
}

#container {
width: 100%;
height: 100vh;
}

...

Override scroll up/down function if scrollTop is equal to 0

Here you go: just add a catch for when the scrollTop value is 0.

  $(window).scroll(
{
previousTop: 0
},
function () {
var currentTop = $(window).scrollTop();
if (currentTop < this.previousTop ) {
if (currentTop != 0 ) { // new if statement here prevents fadein if at top of page
header.fadeIn('slow');
header.css('background', 'rgba(0,0,0,.9)');
}
} else {
header.fadeOut();
}
this.previousTop = currentTop;
});


Related Topics



Leave a reply



Submit