我有一个标头设置为 position: fixed
的站点。在我的一个页面上,我在一个元素上使用了 scrollIntoView(true)
。我的问题是,当调用 scrollIntoView
时,元素被定位在标题下方。我将如何解决这个问题,以便元素显示在标题下方?
我正在使用 Bootstrap 框架,并且标头的样式为 navbar navbar-fixed-top
。
我有一个标头设置为 position: fixed
的站点。在我的一个页面上,我在一个元素上使用了 scrollIntoView(true)
。我的问题是,当调用 scrollIntoView
时,元素被定位在标题下方。我将如何解决这个问题,以便元素显示在标题下方?
我正在使用 Bootstrap 框架,并且标头的样式为 navbar navbar-fixed-top
。
这有点老套,但这里有一个解决方法。
var node = 'select your element';
var yourHeight = 'height of your fixed header';
// scroll to your element
node.scrollIntoView(true);
// now account for fixed header
var scrolledY = window.scrollY;
if(scrolledY){
window.scroll(0, scrolledY - yourHeight);
}
编辑:
现代的解决方法是结合使用 CSS scroll-margin-top
属性和 :target
选择器。详细描述: https://www.bram.us/2020/03/01/prevent-content-from-being-hidden-underneath-a-fixed-header-by-using-scroll-margin-top/
以下代码产生一个平滑滚动到元素顶部的固定标题偏移量:
var topOfElement = document.querySelector('#targetElement').offsetTop - XX;
window.scroll({ top: topOfElement, behavior: "smooth" });
其中 XX 是固定标题的高度。
对于现代浏览器:在您要链接/滚动到的元素上,将 scroll-margin-top
css 属性设置为所需的顶部偏移量。 (它可能应该被称为 scroll-offset-top。)
* {
scroll-margin-top: 100px;
}
Docs - Works in modern browsers - Codepen demo
links = [...document.getElementsByClassName("js-link")]
links.forEach(element => {
element.addEventListener("click", e => {
e.preventDefault()
document.getElementById(e.target.dataset.target).scrollIntoView({
behavior: "smooth",
block: "start",
inline: "nearest"
})
})
})
body {
margin: 0;
}
header {
position: sticky;
top: 0;
left: 0;
right: 0;
height: 100px;
background: #eee;
display: flex;
align-items: center;
}
header a {
padding: 0.5em;
}
h1 {
padding: 0.7em;
}
* {
scroll-margin-top: 100px;
}
p {
padding: 1em;
}
<header>
<h1>page title</h1>
<nav>
<a href="#p1" class="js-link" data-target="p1">1</a>
<a href="#p2" class="js-link" data-target="p2">2</a>
<a href="#p3" class="js-link" data-target="p3">3</a>
<a href="#p4" class="js-link" data-target="p4">4</a>
<a href="#p5" class="js-link" data-target="p5">5</a>
</nav>
</header>
<main>
<p id="p1">
paragraph 1.
<br> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
publishing software like Aldus PageMaker including versions of Lorem Ipsu
</p>
<p id="p2">
paragraph 2.
<br> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
publishing software like Aldus PageMaker including versions of Lorem Ipsu
</p>
<p id="p3">
paragraph 3.
<br> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
publishing software like Aldus PageMaker including versions of Lorem Ipsu
</p>
<p id="p4">
paragraph 4.
<br> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
publishing software like Aldus PageMaker including versions of Lorem Ipsu
</p>
<p id="p5">
paragraph 5.
<br> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
publishing software like Aldus PageMaker including versions of Lorem Ipsu
</p>
</main>
尝试以下操作。这对我来说很有效:
const headerHeight = 50; /* PUT HEADER HEIGHT HERE */
const buffer = 25; /* MAY NOT BE NEEDED */
const scrollToEl = document.querySelector("#YOUR-ELEMENT-SELECTOR");
const topOfElement = window.pageYOffset + scrollToEl.getBoundingClientRect().top - headerHeight - buffer;
window.scroll({ top: topOfElement, behavior: "smooth" });
如果有人在 scrollIntoView 之后遇到容器 div 的上边距被忽略的问题,那么与其将元素滚动到视图中,不如相对于其父滚动容器执行 scrollTop,如下所示:
var topOfElementToView= $('#elementToScroll').position().top;
$('#parentScrollingContainer').scrollTop(topOfElementToView);
得到了 user113716 在此线程上的答案: How to go to a specific element on page?
我怀疑对个人有用的东西在很大程度上取决于他们的页面布局,所以这个答案旨在作为一个额外的选择而不是篡夺任何人。
我需要做的就是传递 false 以滚动到视图 scrollIntoView(false)
it('should be able to click a button selector', function () {
let EC = protractor.ExpectedConditions;
let button = element(by.css('.my-button-css));
browser.executeScript('arguments[0].scrollIntoView(false)', button.getWebElement()).then(function () {
browser.wait(EC.elementToBeClickable(button), 3000).then(function () {
expect(button.isDisplayed()).toBeTruthy();
button.click();
// more test logic here
});
});
});
感谢 reboot jeff
如果有人修复了滚动后隐藏 HeaderTitle 的导航栏,这里是解决方案(基于 @coco puffs
的答案和 this one ):
let anchorLinks = document.querySelectorAll('a[href^="#"]')
for (let item of anchorLinks) {
item.addEventListener('click', (e) => {
let hashVal = item.getAttribute('href')
let topOfElement = document.querySelector(hashVal).offsetTop - 70
window.scroll({ top: topOfElement, behavior: "smooth" })
history.pushState(null, null, hashVal)
e.preventDefault()
})
}
在代码中使用了 70px
。
对我来说,将元素滚动到窗口的中心是可行的。
scrollIntoViewIfNeeded({ block: "center" })
很好地做到了这一点,但不幸的是只有有限的浏览器兼容性 ( https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoViewIfNeeded )。它不适用于 IE 和 Firefox。
但是,您可以很容易地自己构建此函数:
function scrollIntoCenter(element) {
// first scroll element into view. This means element is at the very top.
element.scrollIntoView();
// calculate new scrollYPosition by subtracting half of window-height
let y = window.scrollY - window.innerHeight/2;
// scroll up by half of window height
window.scroll(0, y);
}
编辑: 虽然不太兼容(不兼容 IE),
scroll-margin-top
也会解决这个问题,如 Arye Eidelman's answer 中所述。您可以使用 CSS 解决此问题,方法是对要滚动到的元素应用
padding-top
和负数margin-top
。Demo