Проблема
Используемая вами функция scrollIntoView
работает так, как задумано. Однако, поскольку вы прокручиваете только до top элемента, верхняя часть скрыта липкой панелью навигации position: fixed
. Что мы можем сделать, чтобы решить это? Отрегулируйте положение прокрутки после использования scrollIntoView
.
Обходной путь
Вы спросили, как получить высоту элемента после прокрутки мимо него. Вы хотели получить высоту элемента, чтобы можно было регулировать положение прокрутки после использования scrollIntoView
. Однако это не обязательно. Просто добавьте класс (или встроенный стиль), который увеличивает высоту navbar
, затем измерьте его высоту, а затем отмените сделанные вами изменения (я сделал это на var stickyHeight = ...
).
После у вас есть высота липкого элемента, вы можете перенастроить положение прокрутки после использования scrollIntoView
(вычитая липкую высоту навигационной панели из позиции после того, как scrollIntoView
произойдет). Однако все еще есть проблемы: когда вы нажимаете на заголовок, когда навигационная панель еще не зафиксирована, и первый элемент.
Почему щелкает заголовок, когда навигационная панель не исправлена проблема? Это связано с тем, что перед настройкой панели навигации на position: fixed
он все еще находится в нормальном потоке документа, а его высота изменяет высоту документа. Когда он зафиксирован, он выходит из обычного потока документов, а его высота удаляется из высоты документа. Это означает, что мы должны перенастроить формулу вычитания, когда это произойдет. Я сделал это в следующем решении.
Почему проблема с первым элементом? Ну, это в основном из-за дизайна, который вы хотите. Вы просто не можете показать самую верхнюю часть элемента, пока полоска заклеена. Попробуйте очень медленно прокрутить вручную, чтобы понять, что я имею в виду.
Решение
Вот рабочее решение. Попробуйте запустить его.
window.onscroll = function() {
myFunction()
};
var navbar = document.getElementById("navbar");
var sticky = navbar.offsetTop;
// Getting sticky and nonStickyHeight for scroll readjustments
var nonStickyHeight = navbar.scrollHeight
var stickyHeight = (() => {
navbar.style.padding = "40px 16px" // Or add the class that adds padding
let result = navbar.scrollHeight
navbar.style.padding = '' // Or remove the class that adds padding
return result
})()
function myFunction() {
if (window.pageYOffset >= sticky) {
navbar.classList.add("sticky")
document.getElementById("navbar").style.padding = "40px 16px";
} else {
navbar.classList.remove("sticky");
document.getElementById("navbar").style.padding = "25px 16px";
}
}
function headerClick(elem) {
let firstElementClicked = false
let navbarIsSticky = false
// Check if navbar is stickied when the headings are clicked
if (navbar.scrollHeight === stickyHeight) navbarIsSticky = true
if (elem.innerHTML === 'This is One') {
document.getElementById("One").scrollIntoView();
firstElementClicked = true
}
if (elem.innerHTML === 'This is Two') {
document.getElementById("Two").scrollIntoView();
}
if (elem.innerHTML === 'This is Three') {
document.getElementById("Three").scrollIntoView();
}
if (elem.innerHTML === 'This is Four') {
document.getElementById("Four").scrollIntoView();
}
// If the navbar is stickied and it's not the first element, just subtract the stickyHeight from the scroll position
if (!firstElementClicked && navbarIsSticky) window.scroll(window.pageXOffset, window.pageYOffset - stickyHeight - 5)
else if (firstElementClicked && !navbarIsSticky)
window.scroll(window.pageXOffset, window.pageYOffset - nonStickyHeight)
// If the navbar is not stickied, you have to take account the nonStickyHeight that will be removed from the document's height when the navbar is stickied
else if (!navbarIsSticky) window.scroll(window.pageXOffset, window.pageYOffset - nonStickyHeight - stickyHeight - 5)
}
* {
/*scroll-behavior: smooth;*/
}
body {
margin: 0;
font-size: 28px;
}
#navbar {
overflow: hidden;
background-color: #333;
padding: 25px 16px;
}
#navbar a {
float: left;
display: block;
color: #f2f2f2;
text-align: center;
text-decoration: none;
font-size: 17px;
margin-right: 15px;
}
.content {
padding: 16px;
}
.sticky {
position: fixed;
top: 0;
width: 100%;
z-index: 100;
box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.16);
}
.common {
border: 1px solid black;
padding: 200px 10px;
margin-bottom: 20px;
}
<body>
<div class="header">
<p>Scroll down to see the sticky effect.</p>
</div>
<div id="navbar">
<a onclick="headerClick(this); return false;" href="#">This is One</a>
<a onclick="headerClick(this); return false;" href="#">This is Two</a>
<a onclick="headerClick(this); return false;" href="#">This is Three</a>
<a onclick="headerClick(this); return false;" href="#">This is Four</a>
</div>
<div class="content">
<div class="common" id="One">This is the first</div>
<div class="common" id="Two">Two</div>
<div class="common" id="Three">Three</div>
<div class="common" id="Four">Four</div>
<div class="common" id="Five">Five</div>
<div class="common">Filler div to make scrolling longer</div>
<div class="common">Filler div to make scrolling longer</div>
<div class="common">Filler div to make scrolling longer</div>
</div>
</body>