Изменяется window.scroll при добавлении элемента

Пытаюсь реализовать меню, которое будет приклеено к верхней части экрана, если пользователь прокрутил страницу вниз. Высота меню - 74px;

componentDidMount() {
    window.addEventListener('scroll', () => {
        console.log(window.scrollY);
        if (window.scrollY >= 700) {
            this.setState({ className: 'navbar fixed' });
        } else {
            this.setState({ className: 'navbar' });
        }
    });
}

Когда прокрутка доходит до window.scrollY = 700, к меню добавляется класс fixed, оно отображается, но window.scrollY становится равен 626 (700 минус высота меню(74)), и меню начинает очень быстро появляться и исчезать, console.log(window.scrollY) попеременно отображает то 700 то 626.

Если прокрутить ещё ниже - проблема исчезает, и меню стабильно отображается и не "скачет"


Ответы (2 шт):

Автор решения: Vladislav Belozerov

Присвойте меню изначально position: absolute. Тогда его высота не будет учитываться. А контент сдвиньте вниз на значение равное высоте меню. Посмотрите пример.

const componentDidMount = () => {
    window.addEventListener('scroll', () => {
        const nav = document.querySelector("nav");
        if (window.scrollY >= 700) {
            nav.classList.add("fixed");
        } else {
             nav.classList.remove("fixed");
        }
    });
}

componentDidMount();
body {
  margin: 0;
}
main {
  height: 1000vh;
  background: green;
  margin-top: 74px;
}
nav {
  width: 100%;
  height: 74px;
  background: red;
  position: absolute;
  top: 0;
}
.fixed {
  position: fixed;
}
<nav></nav>
<main></main>

→ Ссылка
Автор решения: Дарья В.

В 2020 году можно смело использовать position:sticky :)

Ваш ответ натолкнул меня на другое решение: Записать в html второе, такое же меню, но изначально задать ему класс hide с display:none, а при прокрутке window.scrollY >= 700, через стейт менять класс второго меню на fixed

Можно поступить проще - добавить дополнительную обертку для меню и задать ей такую же высоту как и меню. В этом случае, меню будет менять position между значениями static/fixed, а обертка всегда будет static и при этом иметь высоту меню. Это предотвратит "скачки" при скроллинге

→ Ссылка