不会撞击浏览器窗口的哈希标签链接

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您的旅程的每个阶段提供云产品。 立即开始使用 200 美元免费积分!

当链接包含一个哈希值,例如这样

<a href="#section-two">Section Two</a>

浏览器窗口将立即滚动到一个位置,使 ID 为“section-two”的元素可见。 它会滚动到最小的可能位置,使该元素完全可见。 通常这需要将窗口向下滚动,但请注意,如果任何可滚动的父容器需要水平滚动才能使元素可见,浏览器也会执行该操作。 我将这称为“顶撞”浏览器,因为该元素与浏览器窗口的顶边缘齐平。

这可能

  • 在美学上不悦
  • 令人困惑(尤其是在跳到一个包含大量其他标题的区域时)
  • 在固定定位的始终置顶标题的情况下,问题非常严重

固定定位标题是最严重的威胁,因此让我们以它为例并解决它。

更新! 只需使用 scroll-margin-top

这正是 scroll-margin-top 属性的设计目的。 顾名思义,它在滚动事件后为元素添加顶部边距。 因此,如果我们想要在视窗顶部和元素之间有 50px 的空间,我们可以执行以下操作

但是等等! 如果您点击该锚点链接,但什么也没有发生,很可能是因为您使用的是 Safari 11 或更早版本(macOS 或 iOS)。 为了支持这些浏览器,我们需要将它与 scroll-snap-margin-top 配合使用,这是一个旧版本的属性

h2 {
  scroll-margin-top: 50px;
  scroll-snap-margin-top: 50px; /* iOS 11 and older */
}

/* If the browser supports the property... */
@supports (scroll-margin-top: 0;) {
  h2 {
    scroll-margin-top: 50px;
  }
}

所有其他方法都来自这篇文章的原始版本,该版本于 2010 年发布。

坚如磐石(脏 HTML)方法

与其像往常一样首先关注最先进的方法,不如让我们看看最有可能跨浏览器兼容的实现方法。

我们不会将 ID 放置在标题上,而是将其放在标题内的空 span 标签上。 这完全不会影响标题的外观。 但是,将 span 用于像这样的纯粹行为事物并非理想。

<a href="#goto">Jump</a>

<!-- yadda yadda yadda -->

<h2>
   <span id="goto">   </span>
   Header
</h2>

然后在 CSS 中,我们将使用负的顶部边距将 span 吸收到实际标题的北部。 然后,我们将通过正的底部填充将标题推回,从而缓解吸取操作造成的任何奇怪的布局问题。

h2 span { 
  margin-top: -300px; /* Size of fixed header */
  padding-bottom: 300px; 
  display: block; 
}

理想情况下,我们只需将 span 绝对定位在标题顶部,但 IE7 不支持这种做法,完全忽略了跳转。 IE6 在固定定位方面存在重大问题,因此此演示在 IE6 中是无效的,让我们不要这样做,尽管我相信如果你能解决固定定位问题,这个想法基本上是可行的。

更花哨(干净 HTML)方法

使用额外的 span 由于两个原因是非语义的:(1) 您将链接直接关联到一个空 span,这是毫无意义的。(2) span 根本不应该在那里。 HTML 应该是

<a href="#goto">Jump</a>

<!-- yadda yadda yadda -->

<h2 id="goto">Header</h2>

然后为了解决顶撞/填充问题,我们将使用一个伪元素来执行 span 在我们的脏 HTML 版本中所做的相同任务。 我们将赋予它一个高度,这会向上推动标题的大小,然后使用负边距将其拉回到位。

h2::before { 
  display: block; 
  content: " "; 
  margin-top: -285px; 
  height: 285px; 
  visibility: hidden; 
  pointer-events: none;
}

来自 Nicolas Gallagher 的更多信息

我在 Forrst 上发布了这个想法的原始版本,Nicolas Gallagher 接受了它并继续研究,就像 Nic 喜欢做的那样 =)。 他指出,如果标题上有背景,并且您不希望背景扩展,则高度/边距技术可能存在问题。 他通过实验使用 background-clip、使用底部边框和其他方法来防止这种情况。 同时要感谢 Ira McMahon 在 Forrst 上激发了这个想法。

作为 Nic 演示的一部分,他使用 :target 在“跳跃”后更改标题的颜色。 这很好地提醒了我们这个伪选择器,它是一种**完美**的用途。 目标将在 URL 中的哈希标签与元素的 ID 匹配时匹配。 快速提醒:如果 URL 是 http://blahblahblah.com/#header-one 并且存在一个类似于 的元素

怎么了

那么此选择器将匹配 h2:target { background: yellow; }

来自 Patrick Strietzel 的更多信息

我发现 IE7 的哈希标签行为(忽略 padding-top)可以通过将 display 值设置为 inline-block 来欺骗。

h2 { 
  margin-top: -285px; 
  padding-top: 285px; 
  display: inline-block;
}

当然,像这样的 display 更改会产生后果。 inline-blockblock 大不相同,因此请注意。

来自 Kirk Gleffe 的更多信息

Kirk 找到了一种方法,只需使用边距和少量的 transition-delay 就可以实现。

来自 Alex Wolfe 的更多信息

Alex 写信说,标题上的填充可能位于其上方的文本之上。 这意味着它可能会阻止点击或选择文本。 您可以通过 z-index 解决,方法是将文本包装在具有更高 z-index 的东西中,或者,可能是在标题上使用负 z-index