固定页眉与页内锚点重叠

Posted

技术标签:

【中文标题】固定页眉与页内锚点重叠【英文标题】:Fixed page header overlaps in-page anchors 【发布时间】:2011-05-04 10:05:54 【问题描述】:

如果我在 html 页面中有一个非滚动标题,固定在顶部,具有定义的高度:

有没有办法使用 URL 锚点(#fragment 部分)让浏览器滚动到页面中的某个点,但仍然尊重固定元素的高度 没有 JavaScript 的帮助?

http://example.com/#bar
错误(但常见的行为):正确: +----------------------------------+ +-------------- ------------------+ | BAR/////////////////// 标题 | | ///////////////////// 标题 | +----------------------------------+ +-------------- ------------------+ |这是文本的其余部分 | |酒吧 | | ... | | | | ... | |这是文本的其余部分 | | ... | | ... | +----------------------------------+ +-------------- ------------------+

【问题讨论】:

相关:***.com/questions/10732690/… css-tricks.com/hash-tag-links-padding @ax 是的,这是最好的答案。还要检查其中的nicolasgallagher.com/jump-links-and-viewport-positioning/demo。这对我来说效果最好:.dislocate50px, #bar padding: 50px 0 0; margin: -50px 0 0; -webkit-background-clip: content-box; background-clip: content-box; 我正在寻找一种解决方案,它 * 适用于来自同一页面或其他页面的锚点,* 并调整向下翻页按键,以便内容不会被标题剪切,*并允许 sib-div 页脚使用 content-div 向上滚动。还没找到解决办法!但我必须说,我认为正确的方法是针对整个内容 div,而不是每个单独的锚。 ***.com/questions/51070758/… @ax. CSS-tricks.com 有一篇关于scroll-padding-top 的更好的新文章:css-tricks.com/… 相应答案:***.com/a/56467997/247696 【参考方案1】:

我没有看到仅使用 :target 作为选项列出的选项。我发现了

:target margin-top: -100px; padding-top: 100px;

似乎在提供的场景中工作。 :target 也兼容所有现代浏览器。 https://caniuse.com/?search=%3Atarget

【讨论】:

这很有用!【参考方案2】:

从 2021 年 4 月起,将推出单一的非 hacky 且完全跨浏览器的解决方案:

h1 
  scroll-margin-top: 50px

它是CSS Scroll Snap spec 的一部分。在all modern browsers 上运行。

【讨论】:

scroll-padding-topscroll-margin-top有什么区别? 在 Safari 中它被称为 scroll-snap-margin-top: caniuse.com/#search=scroll-margin-top 这个对我有用,但不适用于 Firefox for Linux 78 版。 现已在 Safari TP 中修复。 在 14.1 中发布,现在完全跨浏览器了!【参考方案3】:

我遇到了同样的问题。 我通过向锚元素添加一个类来解决它,顶部栏高度作为 padding-top 值。

<h1><a class="anchor" name="barlink">Bar</a></h1>

我使用了这个 CSS:

.anchor  padding-top: 90px; 

【讨论】:

@Tomalak 请注意,此解决方案使填充区域内的链接不可点击。要解决此问题,您必须使用 z-index,并将链接值设置为高于锚点的值。记住你的 topbar 应该有最高的 z-index 值,所以当你滚动时页面的内容不会浮动在 topbar 上。 由于 WebKit fixed position bug 导致标头消失,因此无法在 Chrome v28 中使用。 This answer 解决了我的问题。 MuttenXd.. 你是我的英雄。我的网站上有奇怪的非功能链接问题(与锚无关)让我发疯。你不可点击的评论真的很有帮助。我欠你的大! 按照 Roy Shoa 的回答中的建议,添加 margin-top: -90px; 以抵消填充造成的差距。 我使用了.anchor:target padding-top: 90px;,所以它只在他们使用锚标签时添加了填充。这样,如果页面加载在顶部,并不总是有一堆填充。仅当它加载页面上较低的特定点时。【参考方案4】:

我用锚元素的滚动边距顶部属性解决了我的问题

scroll-margin-top: 100px;

https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-margin-top

【讨论】:

【参考方案5】:

这里的最佳答案创建了一个 60 像素高的标签,它掩盖了其他因此而停止工作的链接。我发现this solution 没有副作用。

<a class="anchor" id="top"></a>

a.anchor 
    display: block;
    position: relative;
    top: -60px;
    visibility: hidden;

【讨论】:

【参考方案6】:

您现在可以使用scroll-margin-top,即pretty widely adopted。

只需将以下 CSS 添加到您要滚动到的元素:

.element 
  scroll-margin-top: 2em;

【讨论】:

scroll-margin-top 已被建议earlier in this thread 滚动边距不适用于滚动到片段目标...这不适用于锚标签developer.mozilla.org/en-US/docs/Web/CSS/scroll-margin-top 完美运行。我在一些单元格上有一张大桌子和 span#anchors。已设置 td span[id] scroll-margin-top: 80px; 并且它可以正常工作,并完全使用此偏移量滚动。比带有边距和内边距的伪元素的渲染速度要快得多。 在Safari中很久没用了,现在TP中已经修复了。见github.com/mdn/browser-compat-data/issues/… 这是我最喜欢的角色::target scroll-margin-top: 2em; 【参考方案7】:

我觉得这个方法比较有用:

&lt;h2 id="bar" title="Bar"&gt;Bar&lt;/h2&gt;

[id]:target 
    display: block;
    position: relative;
    top: -120px;
    visibility: hidden;


[id]:target::before 
    content: attr(title);
    top: 120px;
    position: relative;
    visibility: visible;

【讨论】:

【参考方案8】:
html 
  scroll-padding-top: 70px; /* height of sticky header */

来自:https://css-tricks.com/fixed-headers-on-page-links-and-overlapping-content-oh-my/

【讨论】:

浏览器支持:caniuse.com/#feat=mdn-css_properties_scroll-padding-top 这不适用于在 Edge 和 Safari (bugs.webkit.org/show_bug.cgi?id=179379) 中滚动整个页面。 救世主!简单,重点。其他解决方案都不适合我,因为我使用的是 display:flex。非常感谢,尝试所有解决方案真是令人沮丧。 可能是我见过的最好的解决方案。 这应该是现在公认的答案。市场已经迎头赶上。【参考方案9】:

刚刚发现了另一个纯 CSS 解决方案,它对我来说就像一个魅力!

html 
  scroll-padding-top: 80px; /* height of your sticky header */

发现于this site!

【讨论】:

其他一些人在您之前发现了此解决方案,请参阅第 1 页上的答案,例如 ***.com/a/56467997/18771 对不起,没注意!谢谢! 这不适用于在 Edge 和 Safari (bugs.webkit.org/show_bug.cgi?id=179379) 中滚动整个页面。【参考方案10】:

我对上面列出的答案没有任何运气,最终使用了这个完美运行的解决方案......

在您要设置锚点的位置创建一个空白跨度。

<span class="anchor" id="section1"></span>
<div class="section"></div>

并应用以下类:

.anchor 
  display: block;
  height: 115px;       /* same height as header */
  margin-top: -115px;  /* same height as header */
  visibility: hidden;

即使这些部分具有不同颜色的背景,此解决方案也可以工作!我在this link.找到了解决方案

【讨论】:

这不正是Guillaume Le Mière 和其他一些人在这个帖子中展示的方法吗? 它非常相似,但我认为它更容易理解,并且响应更详细,并带有更深入的外部来源链接。 这是相同的解决方案,但我可以轻松理解和遵循这个解决方案。其他人没有给我足够的信息。【参考方案11】:

添加一个带有“paddingtop”的类,这样它就可以工作了;)

<h1><a class="paddingtop">Bar</a></h1>

对于 css 你有:

.paddingtop  
   padding-top: 90px; 

【讨论】:

【参考方案12】:

我需要一些适用于入站链接、页面上的链接以及 JS 可以定位的东西,以便页面可以响应标题高度的变化

HTML

<ul>
  <li><a href="#ft_who">Who?</a></li>
  <li><a href="#ft_what">What?</a></li>
  <li><a href="#ft_when">When?</a></li>
</ul>
...
<h2 id="ft_who" class="fragment-target">Who?</h2> 
...
<a href="#">Can I be clicked?</a>
<h2 id="ft_what" class="fragment-target">What?</h2>
...
<h2 id="ft_when" class="fragment-target">When?</h2> 

CSS

.fragment-target 
    display: block;
    margin-top: -HEADER_HEIGHTpx;
    padding-top: HEADER_HEIGHTpx;
    z-index: -1;

z-index: -1 允许片段目标上方“填充区域”中的链接仍然可以点击,正如 @MuttenXd 在他的回答中所评论的那样

我尚未在 IE 11、Edge 15+、Chrome 38+、FF 52+ 或 Safari 9.1+ 中发现问题

【讨论】:

【参考方案13】:

使用了这个脚本

$(document).on('click', 'a[href^="#"]', function (event) 
    event.preventDefault();

    $('html, body').animate(
        scrollTop: $($.attr(this, 'href')).offset().top -140
    , 1000);
);

【讨论】:

请尝试解释为什么您认为这个脚本可以解决问题【参考方案14】:

我在这里和其他地方的许多答案都遇到了很多麻烦,因为我的书签锚是常见问题页面中的部分标题,因此偏移标题并没有帮助,因为其余内容只会留在原处。所以我想我会发帖。

我最终做的是几个解决方案的组合:

    CSS:

    .bookmark 
        margin-top:-120px;
        padding-bottom:120px; 
        display:block;
    
    

“120px”是您的固定标题高度(可能加上一些边距)。

    书签链接 HTML:

    <a href="#01">What is your FAQ question again?</a>
    

    书签内容 HTML:

    <span class="bookmark" id="01"></span>
    <h3>What is your FAQ question again?</h3>
    <p>Some FAQ text, followed by ...</p>
    <p>... some more FAQ text, etc ...</p>
    

这个解决方案的好处是 span 元素不仅是隐藏的,它本质上是折叠的,不会填充您的内容。

我不能对这个解决方案给予太多赞誉,因为它来自大量不同的资源,但在我的情况下它最适合我。

你可以看到实际结果here。

【讨论】:

非常感谢您的分享!尽管线程很老,但似乎仍然没有一个规范的解决方案来解决这个问题。 +SteveCinq 你读懂了我的想法——我遇到了同样的问题,共享解决方案无法按预期工作。在跨度中添加带有锚点的&lt;span&gt;,以及添加填充和边距对我有用。非常感谢您抽出宝贵时间提交此答案,尽管线程已经过时了! 在尝试了这么多不同的技术之后,我打算添加类似的东西,我最终有了相同的想法。在任何应该作为锚点的 div 开始之后,我只包含一个带有锚点类的 span 元素和它的 id。我实际上使用了这些属性: content: " ";显示:块;位置:相对;填充顶部:100px;边距顶部:-100px;可见性:隐藏;指针事件:无;【参考方案15】:

我创建了一个带有几个换行符的 div 并给出了 id,然后我将我想要显示的代码放在下面。然后,该链接会将您带到图像上方的空间,并且标题将不再妨碍您:

<a href="#image">Image</a>
<div id="image"><br><br></div>
<img src="Image.png">

当然,您可以根据需要更改换行符的数量。 这对我来说非常有效,但不确定是否有任何问题,我仍在学习 HTML。

【讨论】:

实用,但有一个缺点 - 它仅适用于页面上的第一个标题。如果有更多标题,您将开始看到文本中有很大的空白,因为每个标题之前都有&lt;br&gt; 标签。【参考方案16】:

如果您不能或不想设置新类,请在 CSS 中为 :target 伪类添加一个固定高度的 ::before 伪元素:

:target::before 
  content: "";
  display: block;
  height: 60px; /* fixed header height*/
  margin: -60px 0 0; /* negative fixed header height */

或者使用 jQuery 滚动相对于:target 的页面:

var offset = $(':target').offset();
var scrollto = offset.top - 60; // minus fixed header height
$('html, body').animate(scrollTop:scrollto, 0);

【讨论】:

这是一个非常适合我的解决方案,不会在我的页面布局中塞满其他任何东西。 CSS 解决方案在与 WebKit 中的列表一起使用时出现问题。看:***.com/questions/39547773/… 如果目标有顶部内边距或边框则不起作用,因为它依赖于margin-collapse。 :target 真是太棒了! 当目标在我的弹性框中时,这不起作用。【参考方案17】:

我觉得最干净的方法是:

  #bar::before 
    display: block;
    content: " ";
    margin-top: -150px;
    height: 150px;
    visibility: hidden;
    pointer-events: none;
  

【讨论】:

【参考方案18】:

使用 jQuery 的最小侵入性方法:

链接:

<a href="#my-anchor-1" class="anchor-link">Go To Anchor 1</a>

内容:

<h3 id="my-anchor-1">Here is Anchor 1</a>

脚本:

$(".anchor-link").click(function() 
    var headerHeight = 120;
    $('html, body').stop(true, true).animate(
        scrollTop: $(this.hash).offset().top - headerHeight
    , 750);
    return false;
);

通过将锚链接类分配给链接,其他链接(如手风琴或选项卡控件)的行为不会受到影响。

这个问题不需要 javascript,但 the other more popular question 因为这个问题而被关闭,我无法在那里回答。

【讨论】:

【参考方案19】:

一个非常简单的 CSS 唯一答案是将其放在样式表的顶部:

apadding-top: 90px;
a:linkpadding-top: unset;

第一种样式规范所有锚标记,其中第二种样式使用超链接锚定标记。

注意:这目前适用于 Firefox 和 Edge,但不适用于 Chrome。

【讨论】:

【参考方案20】:

当您单击导航时,这就是我最终到达正确位置的方法。我为导航点击添加了一个事件处理程序。然后你可以使用“scrollBy”来向上移动偏移量。

var offset = 90;

 $('.navbar li a').click(function(event) 
    event.preventDefault();
    $($(this).attr('href'))[0].scrollIntoView();
    scrollBy(0, -offset);
 );

【讨论】:

解决了问题,但不是“没有 Javascript 的帮助”部分...【参考方案21】:

CSS 技巧将是一种解决方法。可以使用 jQuery 实现适用于所有场景的适当解决方案。

参考https://codepen.io/pikeshmn/pen/mMxEdZ

方法:我们使用 document.getElementById('header').offsetHeight 得到固定导航的高度 并将滚动偏移到这个值。

var jump=function(e)  

e.preventDefault();                        //prevent "hard" jump
  var target = $(this).attr("href");       //get the target

      //perform animated scrolling
      $('html,body').animate(
        
          scrollTop: $(target).offset().top - document.getElementById('header').offsetHeight - 5  //get top-position of target-element and set it as scroll target
        ,1000,function()                  //scrolldelay: 1 seconds
        
          location.hash = target;          //attach the hash (#jumptarget) to the pageurl
        );
      

  $(document).ready(function()
  
    $('a[href*="#"]').bind("click", jump); //get all hrefs
    return false;
  );

PS:

它包括标题和目标之间 5 像素的漂亮差异 滚动效果不硬,比较流畅;平滑滚动

【讨论】:

OP 要求不要使用 javascript。【参考方案22】:

它对我有用:

到锚点的 HTML 链接:

<a href="#security">SECURITY</a>

HTML 锚点:

<a name="security" class="anchor"></a>

CSS:

.anchor::before 
    content: "";
    display: block;
    margin-top: -50px;
    position: absolute;

【讨论】:

【参考方案23】:

使用:before 实现的效果很好,直到我们意识到伪元素实际上覆盖并阻止了位于伪元素区域 的指针事件。在:before 上使用pointer-events: none 之类的东西,甚至直接在锚上都没有影响。

我们最终做的是使锚的定位绝对,然后将其位置调整为固定区域的偏移量/高度。

不阻塞指针事件的偏移锚点

.section-marker 

    position: absolute;
    top: -300px;

这样做的价值是我们不会阻止任何可能落在这 300 像素内的元素。不利的一面是,从 Javascript 中获取该元素的位置需要考虑该偏移量,因此必须调整其中的任何逻辑。

【讨论】:

【参考方案24】:

我使用这种方法是因为出于某种原因,提出的其他解决方案都没有真正适合我。我保证我试过了。

section 
   position: relative;
   border-top: 52px solid transparent; /* navbar height +2 */
   margin: -30px 0 0;
   -webkit-background-clip: padding-box;
   -moz-background-clip: padding;
   background-clip: padding-box;


section:before 
   content: "";
   position: absolute;
   top: -2px;
   left: 0;
   right: 0;
   border-top: 2px solid transparent;

如果您愿意,可以将 section 替换为一个类。

来源:Jump links and viewport positioning

在 Firefox 45 和 Chrome 52 上测试。 引导版本:3.3.7

对于那些不相信我的人,我准备了一个带有解决方案的 jsfiddle:SOLUTION

【讨论】:

【参考方案25】:
// handle hashes when page loads
// <http://***.com/a/29853395>
function adjustAnchor() 
  const $anchor = $(':target');
  const fixedElementHeight = $('.navbar-fixed-top').outerHeight();
  if ($anchor.length > 0)
    window.scrollTo(0, $anchor.offset().top - fixedElementHeight);

$(window).on('hashchange load', adjustAnchor);
$('body').on('click', "a[href^='#']", function (ev) 
  if (window.location.hash === $(this).attr('href')) 
    ev.preventDefault();
    adjustAnchor();
  
);

【讨论】:

不幸的是,这不符合“没有 Javascript”的限制。【参考方案26】:

我正在使用@Jpsy 的答案,但出于性能原因,我只在 URL 中存在哈希时设置计时器。

$(function() 
      // Only set the timer if you have a hash
      if(window.location.hash) 
        setTimeout(delayedFragmentTargetOffset, 500);
      
  );

function delayedFragmentTargetOffset()
      var offset = $(':target').offset();
      if(offset)
          var scrollto = offset.top - 80; // minus fixed header height
          $('html, body').animate(scrollTop:scrollto, 0);
          $(':target').highlight();
      
  ;

【讨论】:

OP 要求不要使用 javascript。 适用于外部链接,但不适用于页内链接。【参考方案27】:

官方引导采用的答案:

*[id]:before  
  display: block; 
  content: " "; 
  margin-top: -75px; // Set the Appropriate Height
  height: 75px; // Set the Appropriate Height
  visibility: hidden; 

Credits

Merge

【讨论】:

此解决方案在与 WebKit 中的列表一起使用时会出现问题。看:***.com/questions/39547773/… 请注意,如果目标元素本身恰好有display: flex;padding-top,这将不起作用。在这些情况下,请使用专用的锚元素(如 &lt;a name="my_link"&gt;leave this empty&lt;/a&gt;)。 它可以防止点击目标元素上方/之前的链接/元素。之前它可能是两个弊端中最小的一个,但现在人们应该只使用scroll-padding-top【参考方案28】:

我发现我必须同时使用 both MutttenXdBadabam 的 CSS 解决方案,因为第一个在 Chrome 中不起作用第二个在 Firefox 中不起作用:

a.anchor  
  padding-top: 90px;


a.anchor:before  
  display: block;
  content: "";
  height: 90px;
  margin-top: -90px;


<a class="anchor" name="shipping"></a><h2>Shipping (United States)</h2>
...

【讨论】:

【参考方案29】:

对于 Chrome/Safari/Firefox,您可以添加 display: block 并使用负边距来补偿偏移量,例如:

a[name] 
    display: block;
    padding-top: 90px;
    margin-top: -90px;

参见示例http://codepen.io/swed/pen/RrZBJo

【讨论】:

【参考方案30】:

在我的纯粹主义者看来,这有点 hacky,但作为一个纯 CSS 的解决方案,您可以使用 :target 选择器为活动的锚定元素添加填充:

html, body height:100%; min-height:100%; margin:0;
body min-height:200%;
header display:inline-block; position:fixed; font-size:1.5em; height:100px; top:0; left:0; right:0; line-height:100px; background:black; text-align:center;
header a color:#fff;
section padding:30px; margin:20px;
section:first-of-type, section:target padding-top:130px;
<header><a href="#one">#One</a> <a href="#two">#two</a> <a href="#three">#three</a></header>
<section id="one"><h1>One</h1>Aenean lacinia bibendum nulla sed consectetur. Nullam id dolor id nibh ultricies vehicula ut id elit. Integer posuere erat a ante venenatis dapibus posuere velit aliquet.</section>
<section id="two"><h1>Two</h1>Aenean lacinia bibendum nulla sed consectetur. Nullam id dolor id nibh ultricies vehicula ut id elit. Integer posuere erat a ante venenatis dapibus posuere velit aliquet.</section>
<section id="three"><h1>Three</h1>Aenean lacinia bibendum nulla sed consectetur. Nullam id dolor id nibh ultricies vehicula ut id elit. Integer posuere erat a ante venenatis dapibus posuere velit aliquet.</section>

【讨论】:

这根本不是 hacky!很好的解决方案。 这只是在目标部分上方创建了一个巨大的填充空间,您在向上滚动时很容易注意到这一点。非常hacky的解决方案

以上是关于固定页眉与页内锚点重叠的主要内容,如果未能解决你的问题,请参考以下文章

固定页眉和页内锚点与 Tripit Slate

PDF添加页眉页脚用什么工具

THEAD 与打印页眉上的页面内容重叠

内容与 PDF 第二页上的页眉重叠

页眉和页脚幻灯片动画的区别

mpdf - 第一页上的文本延伸到第二页,与页眉重叠