I have an navbar where I use scrollIntoView
to always have the active element in the center of the list. However I discovered when the user scrolls the main content it will interrupt / stop the scrollIntoView. It only works when there is no scrolling from the user. You can in this example: https://jsfiddle.net/2otv6pyx/
(Code is the same as below. However the example bugs a little bit on stackoverflow since it's scrolling the page)
const first = document.querySelector('#first')
const last = document.querySelector('#last')
let atLast = false
setInterval(() => {
if (!atLast) {
last.scrollIntoView({
block: "end",
behavior: "smooth"
})
atLast = true
} else {
first.scrollIntoView({
block: "end",
behavior: "smooth"
})
atLast = false
}
}, 1000)
nav {
position: sticky;
top: 0;
background-color: white;
}
nav>ul {
list-style-type: none;
display: grid;
grid-auto-flow: column;
overflow-x: scroll;
}
nav .active {
color: red
}
nav li {
padding-right: 1rem;
}
p {
line-height: 8rem;
}
<nav>
<ul>
<li id="first">Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li id="last">Sulier</li>
</ul>
</nav>
<main>
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat
nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt
ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse</p>
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat
nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt
ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse</p>
</main>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
I want to be able to scroll the main content without stopping the animation in the navbar. How can I achieve this? Is there a way to force scrollIntoView?
I also noticed when I scroll the whole content down it will first scroll up and than horizontal.
CodePudding user response:
The main issue you are experiencing with your code is that the Element.scrollIntoView
method is forcing the window to scroll, when really you just want the ul
element to scroll.
Instead, the Element.scrollTo
method is a better choice at accomplishing your goal. This method will only scroll the element specified instead of scrolling the window. This allows you to scroll in other places in the window without it conflicting with the scrolling happening in the ul
.
Because we are using this method instead, we have to specify how far we want the element to scroll. Just like .scrollIntoView
, .scrollTo
takes an options object. For your demonstration the left
option is what is important to modify. We could just enter left: 0
to scroll to the beginning, and left: someBigNumber
to scroll to the end, however "magic numbers" are not ideal. Being able to dynamically decide the scroll points is important.
To determine the left
value desired, I called the client rectangle of each element, and stored the left
value provided from the rectangle. However, this left
value is from the perspective of the window
. To offset that left value, I found the left value of the ul
which contains the first
and last
elements, and when passing the value into the options, I subtract the ulLeft
value.
You may notice that the scroll effect goes all the way right but not all the way left. This is because we can not scroll the last element into the beginning of the view, so it stops as far as it can get. The scroll will not go all the way to the left because we are scrolling to the beginning of the first li, and there is space before the first li. Depending on desired effect you could calculate those offset values as well.
A few other things I changed while testing:
Semicolons! Add semicolons at the end of every statement.
Instead of using setInterval
I opted for an async function with a while loop and wait
helper function, because I felt it was more readable.
const first = document.querySelector('li:first-of-type');
const last = document.querySelector('li:last-of-type');
const ul = document.querySelector("ul");
const lastLeft = last.getBoundingClientRect().left;
const firstLeft = first.getBoundingClientRect().left;
const ulLeft = ul.getBoundingClientRect().left;
const wait = () => new Promise(r => setTimeout(r, 2000));
(async () => {
await wait();
while(true) {
ul.scrollTo({
behavior: "smooth",
left: lastLeft - ulLeft
});
await wait();
ul.scrollTo({
behavior: "smooth",
left: firstLeft - ulLeft
});
await wait();
}
})();
nav {
position: sticky;
top: 0;
background-color: white;
}
nav>ul {
list-style-type: none;
display: grid;
grid-auto-flow: column;
overflow-x: scroll;
}
nav .active {
color: red
}
nav li {
padding-right: 1rem;
}
p {
line-height: 8rem;
}
<nav>
<ul>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
<li>Nice</li>
<li>useScroll</li>
<li>Is</li>
<li>Sulier</li>
</ul>
</nav>
<main>
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat
nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt
ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse</p>
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat
nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt
ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse</p>
</main>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>