使用带有固定位置标头的scrollIntoView


72

我有一个标头设置为的网站position: fixed。在我的一页上,我scrollIntoView(true)在一个元素上使用。我的问题是,当scrollIntoView被调用时,该元素位于标头下方。如何解决此问题,以便将元素显示在标题的正下方?

我使用的是Bootstrap框架,标头的样式为navbar navbar-fixed-top

Answers:


88

这有点hacky,但这是一种解决方法。

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);
}

编辑:

一种现代的解决方法是将CSSscroll-margin-top属性与:target选择器结合使用。详细说明:https : //www.bram.us/2020/03/01/prevent-content-from-being-hidden-underneath-a-fixed-header-by-using-scroll-margin-top/


我一直在寻找这个答案几天。终于找到了。凉。
Faisal Mq,2015年

如果标头具有动态大小,还可以设置一个假想的'yourHeight',例如1000。
Pietro Coelho

6
您可以通过执行window.scroll(0, node.offsetTop - yourHeight);和不使用来简化代码scrollIntoView
jhujhul

1
它可以工作,但是不会考虑浏览器的本机平滑滚动行为(如果存在)。
msun

1
我认为最有用的解决方法(而不是滚动到顶部,而是滚动到中心):node.scrollIntoViewIfNeeded({block: 'center'})
Sanyam Jain

36

编辑:虽然较少兼容(无边缘+ IE兼容性),scroll-margin-top也将解决这个问题,如在所提到的答案阿里耶Eidelman

您可以使用CSS来解决此问题,方法是将apadding-top和负数margin-top应用于要滚动到的元素。

演示版

// For demo only, no JS needed for the solution
document.querySelector('.scroll-to-working-inline').addEventListener('click', function() {
  document.querySelector('.working-inline').scrollIntoView();
});

document.querySelector('.scroll-to-working-block').addEventListener('click', function() {
  document.querySelector('.working-block').scrollIntoView();
});

document.querySelector('.scroll-to-broken').addEventListener('click', function() {
  document.querySelector('.broken').scrollIntoView();
});
/* Relevant styles */
.working-inline {
  padding-top: 60px;
  margin-top: -60px;
}

.working-block {
  padding-top: 60px;
  margin-top: -60px;
}

/* Allow scrolling to the top */
body {
  padding-top: 60px;
}

/* Only for the demo */
body { margin: 0; }

header {
  position: fixed;
  top: 0;
  background-color: tomato;
  color: white;
  width: 100%;
  height: 60px;
  line-height: 60px;
  text-align: center;
}

[class^='working'],
[class^='broken'] {
  font-size: 3rem;
}
<header>
  scroll to...
  <button class="scroll-to-working-inline">working inline element</button>
  <button class="scroll-to-working-block">working block element</button>
  <button class="scroll-to-broken">broken element</button>
</header>

<main>
  <p>Sql daemon epoch all your base are belong to us packet system perl semaphore. Interpreter warez pragma kilo worm back door baz continue chown blob unix Dennis Ritchie stack mutex bar throw fopen man pages linux. Sql suitably small values bit infinite loop pwned rm -rf.</p>
  
  <a class="working-inline">Working inline</a>
  
  <p>Syn baz man pages unix vi crack leapfrog semaphore fail pwned afk null socket cd long leet emacs Donald Knuth bin grep todo pragma stdio.h January 1, 1970. Alloc gc system new finally sql stack trace syn mainframe cat machine code memory leak server salt flood tunnel in back door thread. Bytes fatal throw ctl-c Dennis Ritchie over clock eof tera perl regex.</p>
  
  <div class="working-block">Working block element</div>
  
  <p>Public injection class unix malloc error script kiddies packet less fail int I'm sorry Dave, I'm afraid I can't do that. Tarball memory leak double rsa pwned public all your base are belong to us. False bytes bang bar tarball semaphore warez cd port daemon exception mountain dew sql mainframe gcc ifdef chown private.</p>
  
  <div class="broken">Broken element</div>
  
  <p>Daemon bubble sort protected mutex overflow grep snarf crack warez I'm compiling bit if memory leak Starcraft nak script kiddies long it's a feature. Hello world public server James T. Kirk injection terminal wannabee race condition syn alloc. Gobble leapfrog finally bypass concurrently while irc gurfle do back door blob man pages sql over clock.</p>
  
  <p>Char hello world then man pages ascii long salt while char fatal do boolean tunnel in system else foo packet sniffer float terminal int default. Trojan horse ssh ifdef /dev/null chown cache error protocol afk todo rm -rf mainframe piggyback pwned regex xss warez Starcraft try catch stdio.h bubble sort. It's a feature I'm sorry Dave, I'm afraid I can't do that *.* port bypass ip.</p>
  
  <p>Stdio.h epoch mutex flood wannabee do race condition sql access exception. Bar pragma man pages dereference flush todo highjack while buffer bit nak big-endian syn xss salt for d00dz. Leslie Lamport linux server error hexadecimal snarf tunnel in rm -rf firewall then shell all your base are belong to us.</p>

  <p>Ascii gcc grep int flood kilo linux access mailbomb hash *.* fork semaphore frack else win bar ssh Leslie Lamport. Man pages strlen cache gnu segfault tarball race condition perl packet sniffer root cookie private chown d00dz January 1, 1970. Rsa public crack bit warez throw for void concurrently ip mutex.</p>
  
  <p>Char hello world then man pages ascii long salt while char fatal do boolean tunnel in system else foo packet sniffer float terminal int default. Trojan horse ssh ifdef /dev/null chown cache error protocol afk todo rm -rf mainframe piggyback pwned regex xss warez Starcraft try catch stdio.h bubble sort. It's a feature I'm sorry Dave, I'm afraid I can't do that *.* port bypass ip.</p>
  
  <p>Stdio.h epoch mutex flood wannabee do race condition sql access exception. Bar pragma man pages dereference flush todo highjack while buffer bit nak big-endian syn xss salt for d00dz. Leslie Lamport linux server error hexadecimal snarf tunnel in rm -rf firewall then shell all your base are belong to us.</p>

  <p>Ascii gcc grep int flood kilo linux access mailbomb hash *.* fork semaphore frack else win bar ssh Leslie Lamport. Man pages strlen cache gnu segfault tarball race condition perl packet sniffer root cookie private chown d00dz January 1, 1970. Rsa public crack bit warez throw for void concurrently ip mutex.</p>
  
  <p>Char hello world then man pages ascii long salt while char fatal do boolean tunnel in system else foo packet sniffer float terminal int default. Trojan horse ssh ifdef /dev/null chown cache error protocol afk todo rm -rf mainframe piggyback pwned regex xss warez Starcraft try catch stdio.h bubble sort. It's a feature I'm sorry Dave, I'm afraid I can't do that *.* port bypass ip.</p>
  
  <p>Stdio.h epoch mutex flood wannabee do race condition sql access exception. Bar pragma man pages dereference flush todo highjack while buffer bit nak big-endian syn xss salt for d00dz. Leslie Lamport linux server error hexadecimal snarf tunnel in rm -rf firewall then shell all your base are belong to us.</p>

  <p>Ascii gcc grep int flood kilo linux access mailbomb hash *.* fork semaphore frack else win bar ssh Leslie Lamport. Man pages strlen cache gnu segfault tarball race condition perl packet sniffer root cookie private chown d00dz January 1, 1970. Rsa public crack bit warez throw for void concurrently ip mutex.</p>
</main>


1
非常好的CSS唯一解决方案。
xela84

2
我不敢相信它能很好地工作,非常感谢!
Agu V

28

以下代码可平滑滚动到元素的顶部,并带有固定标头的偏移量:

var topOfElement = document.querySelector('#targetElement').offsetTop - XX;
window.scroll({ top: topOfElement, behavior: "smooth" });

其中XX是固定标头的高度。


为我保存了一天!我使用的mat-card-content是带有amat-toolbar固定标题的可滚动咏叹调。我曾经使用ngx-scroll-to过滚动功能,但在移动设备中无法使用。但是,您的解决方案只能在移动设备上运行,而不能在独立版本上运行,而上述软件包却不能正常运行。结合了和Voila!谢谢!
imans77 '19

可能应该是正确/可接受的答案。谢谢!
20

13

scroll-margin-top:$ header-height;

有一种新的非hacky方法可以实现此操作,该方法适用于标准HTML链接和js scrollIntoView。使用scroll-margin-topCSS属性。

您可以使用CSS属性scroll-margin-top与标题相同的高度。

这不会增加任何可见的边距,但在链接到元素时会在元素上方增加间距。

/*
  Add a scroll-margin-top to all elements that you want to be able to link to.
  (you may need to select items that don't have an id as well)
*/

* {
  scroll-margin-top: 100px;
}

我可以使用scroll-margin-top吗?这适用于大多数现代浏览器(不适用于Safari,IE和旧版本)。

MDN文档scroll-margin-top


我在下面的演示中添加了平滑滚动,因此很明显这是使用scrollIntoView。

在Codepen中查看

links = [ ...document.getElementsByClassName("js-link")]
links.map(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>


不错的解决方案!尽管它似乎对我不起作用,但当我用作的pcss选择器时,效果很好 scroll-margin-top
贝多芬

1
我已对其进行了更新,以仅*在使用javascript或使用元素名称进行链接时选择所有内容。
阿里·艾德曼

6

请尝试以下方法。这对我来说很有效:

  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" });

1

如果在scrollIntoView之后有人遇到容器div的上边距被忽略的问题,那么与其将元素滚动到视图中,不如将其滚动到其父级滚动容器中,就像这样:

var topOfElementToView= $('#elementToScroll').position().top;
$('#parentScrollingContainer').scrollTop(topOfElementToView);

得到了user113716对此线程的答案:如何转到页面上的特定元素?


5
假设jQuery可用。
John Mee

0

如果有人固定了导航栏,该导航栏在滚动后隐藏了Header \ Title,这是解决方案(基于@coco puffs的答案和这一点):

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中使用。


0

我怀疑对个人有效的方法在很大程度上取决于他们的页面布局,因此,此答案仅是一种附加选择,而不是篡改任何人。

我要做的就是传递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

        });
    });
});

多亏了重启杰夫


0

一个很好的简单解决方案(受Sanyam Jain的评论启发)是使用{block: 'center'}垂直居中选择,如下所示:

scrollIntoView({block: 'center'})

编辑-我很遗憾在MDN页面上发现此功能是“实验功能-不应在生产中使用”。另外,IE不支持它(如果需要)。

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.