Javascript 使用带有固定位置标题的 scrollIntoView

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13614112/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 12:29:39  来源:igfitidea点击:

Using scrollIntoView with a fixed position header

javascripttwitter-bootstrap

提问by Corne Beukes

I have a site with a header set to position: fixed. On one of my pages, I use scrollIntoView(true)on an element. My problem is that when scrollIntoViewis called, the element gets positioned underneath the header. How would I fix this so that the element is shown just below the header?

我有一个标题设置为position: fixed. 在我的一个页面上,我使用scrollIntoView(true)了一个元素。我的问题是,当scrollIntoView被调用时,元素被定位在标题下方。我将如何解决这个问题,以便元素显示在标题下方?

I'm using the Bootstrap framework and the header is styled with navbar navbar-fixed-top.

我正在使用 Bootstrap 框架,标题的样式为navbar navbar-fixed-top.

回答by dontmentionthebackup

It's a bit hacky but here's a workaround.

这有点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);
}

Edit:

编辑:

A modern workaround is to use the CSS scroll-margin-topproperty in combination with the :targetselector. Described in detail: https://www.bram.us/2020/03/01/prevent-content-from-being-hidden-underneath-a-fixed-header-by-using-scroll-margin-top/

现代的解决方法是将 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/

回答by Karl Horky

Edit:Although less compatible (no Edge + IE compatibility), scroll-margin-topwill also solve this, as mentioned in the answerfrom Arye Eidelman.

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

You can solve this with CSS, by applying a padding-topand a negative margin-topto the elements that you want to scroll to.

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

Demo

演示

// 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 highHyman 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 highHyman 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 highHyman 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>

回答by Thomas Doucette

The following code yields a smooth scroll to the top of the element with an offset for fixed header:

以下代码使用固定标题的偏移量平滑滚动到元素顶部:

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

Where XX is the height of your fixed header.

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

回答by dipole_moment

Try the following. It works well for me:

请尝试以下操作。这对我来说很有效:

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

回答by Arye Eidelman

scroll-margin-top: $header-height;

滚动边距顶部:$header-height;

There is a new non-hacky way to achieve this that works for standard HTML links and js scrollIntoView. using the scroll-margin-topCSS property.

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

You can use the CSS property scroll-margin-top with the same height as the header.

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

This doesn't add any visible margin but adds spacing above an element when linking to it.

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

/*
  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)
*/

*[id] {
  scroll-margin-top: 100px;
}

Can I use scroll-margin-top?This doesn't work in IE and edge HTML (pre-2020).

我可以使用滚动边距顶部吗?这在 IE 和边缘 HTML(2020 年之前)中不起作用。

MDN docs scroll-margin-top

MDN 文档滚动边距顶部



I've added smooth scrolling to the demo below so it's apparent that this is using scrollIntoView.

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

Veiw in 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"
    })
    // For safari, ie and edge (pre-2020)
    // document.getElementById(e.target.dataset.target).scrollIntoView(true)
  })
})
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;
}

*[id] {
  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>

回答by Johnny

If anybody runs into issues with the top margin of your container div being ignored after a scrollIntoView, then instead of scrolling your element into view, just do a scrollTop relative to its parent scrolling container, as such:

如果有人遇到在 scrollIntoView 之后容器 div 的顶部边距被忽略的问题,那么不要将元素滚动到视图中,只需执行相对于其父滚动容器的 scrollTop,如下所示:

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

Got the answer from user113716 on this thread: How to go to a specific element on page?

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

回答by TitanFighter

In case if someone has fixed navbar which hides Header\Title after scrolling, here is the solution (based on @coco puffs's answer and this one):

如果有人修复了在滚动后隐藏 Header\Title 的导航栏,这里是解决方案(基于@coco puffs's answer 和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()
  })
}

In the code 70pxare used.

在代码70px中使用。

回答by CodeMonkey

I suspect that what will work for the individual will greatly depend on their page layout, so this answer is intended as an additional option rather than to usurp anyone.

我怀疑对个人有用的将在很大程度上取决于他们的页面布局,因此此答案旨在作为附加选项而不是篡夺任何人。

All I needed to do was pass false to scroll into view scrollIntoView(false)

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

        });
    });
});

Thanks to reboot jeff

感谢重新启动杰夫