粘性、平滑、激活导航

Avatar of Chris Coyier
Chris Coyier

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

正如标题所说!这是一个侧边栏导航栏,它……

  1. 使用粘性定位。它尽可能地停留在屏幕上,但不会与页眉、页脚重叠,也不会使任何链接无法访问。
  2. 平滑滚动到您点击的章节。
  3. 根据滚动位置激活当前导航(这是一个单页面内容)。

查看 CodePen 上 Chris Coyier (@chriscoyier) 编写的笔 粘性、平滑、激活导航

粘性

很容易在某个元素上添加 position: sticky; top: 0;。但是为了使其正常工作,它必须位于一个更高的父元素内。因此,导航 (<nav>) 内的无序列表 (<ul>) 在这里非常有效。由于 CSS 网格布局,<nav><main> 内容区域一样高。但是,请注意,我们还必须为 iOS 使用 position: -webkit-sticky;

我还为垂直媒体查询添加了一个 神奇数字,以便它不会以无法访问较低导航项的方式粘贴

/* Only stick if you can fit */
@media (min-height: 300px) {
  nav ul {
    position: sticky;
    top: 0;
  }
}

平滑

在我第一次尝试这个的时候,我考虑过基于 JavaScript 的 平滑滚动。如今它甚至已成为原生功能,无需框架。您可以定位一个元素并平滑地滚动到它

document.querySelector('.hello').scrollIntoView({ 
  behavior: 'smooth' 
});

将其应用于任意一组导航……

let mainNavLinks = document.querySelectorAll("nav ul li a");

mainNavLinks.forEach(link => {
  link.addEventListener("click", event => {
    event.preventDefault();
    let target = document.querySelector(event.target.hash);
    target.scrollIntoView({
      behavior: "smooth",
      block: "start"
    });
  });
});

Chrome 和 Firefox 都支持,但 Edge 和 Safari 不支持。

然后我突然想到,CSS 可以做到这一点!有一个 scroll-behavior 属性,您可以将其放在文档上以使所有内容都以这种方式滚动

html {
  scroll-behavior: smooth;
}

由于我们的导航 <a> 链接是哈希/跳转/锚链接,因此这正是我们所需要的。忘记 JavaScript 吧。特别是由于 scroll-behavior 的浏览器支持.scrollIntoView() 的“平滑”版本相同。

激活

这有点棘手,特别是因为这是一个单页面滚动应用程序,而不是具有自己独立文档的各个页面。如果它们是单独的文档,我们将在导航中的某个位置更改活动类,或者使用 body.specific_page 类或类似的东西。

相反,我们需要查看页面的滚动位置,确定哪个部分处于视野中并以此方式进行标记。可能有一些花哨的 IntersectionObserver 方法可以处理这个问题,但我无法完全理解它,因此我仅仅查看所有相关的部分,进行一些测量和计算,并以此方式确定链接是否处于活动状态。

let mainNavLinks = document.querySelectorAll("nav ul li a");
let mainSections = document.querySelectorAll("main section");

let lastId;
let cur = [];

window.addEventListener("scroll", event => {
  let fromTop = window.scrollY;

  mainNavLinks.forEach(link => {
    let section = document.querySelector(link.hash);

    if (
      section.offsetTop <= fromTop &&
      section.offsetTop + section.offsetHeight > fromTop
    ) {
      link.classList.add("current");
    } else {
      link.classList.remove("current");
    }
  });
});

那里的滚动处理程序应该触发一个小警告标志。这是一种可能应该 节流 的事情,例如,如果您有 lodash 可用

window.addEventListener("scroll", () => {
  _.throttle(doThatStuff, 100);
});

我只是在这里没有这样做,以保持演示的无依赖性。

哦!而且它在移动设备上(这里的 iOS)基本运行良好

JavaScript 库主页的免费模板

我在 我制作的这个模板中使用了所有这些内容,您可以随意使用