JS 特效 词条目录
前端Wiki/JS 特效/导航特效/桌面导航

导航高亮跟随

导航高亮跟随:滚动到某节时,导航对应项自动高亮——常见于文档站与单页应用(SPA)。同样用 IntersectionObserver:观察每个内容区,谁在视口里就高亮谁的导航项。

踩坑点:监听 scroll 计算 getBoundingClientRect 性能差且抖动;正确做法是 IO + rootMargin 微调(如顶部预留 -40% 让高亮提前一点),并用一个观察器批量管理。

  • 每个内容区一个 id,导航项 href="#id" 对应
  • IntersectionObserver + rootMargin 控制高亮时机
  • 滚到页面底部时强制高亮最后一项(边界处理)
HTML
<style>
#sp { display: flex; height: 200px; }
#spnav { width: 110px; display: flex; flex-direction: column; gap: 4px; }
#spnav a { padding: 8px 10px; border-radius: 6px; color: #666;
           text-decoration: none; font-size: 13px; transition: .2s; }
#spnav a.on { background: #d2a8ff; color: #fff; }
#spbody { flex: 1; overflow: auto; padding: 0 16px; }
#spbody section { height: 200px; padding: 16px; box-sizing: border-box; }
</style>
<div id="sp">
  <nav id="spnav">
    <a href="#" data-s="s1">第一节</a><a href="#" data-s="s2">第二节</a>
    <a href="#" data-s="s3">第三节</a>
  </nav>
  <div id="spbody">
    <section id="s1">第一节内容</section>
    <section id="s2">第二节内容</section>
    <section id="s3">第三节内容</section>
  </div>
</div>
<script>
var body = document.getElementById('spbody');
var links = document.querySelectorAll('#spnav a');
var map = {};
links.forEach(function (a) { map[a.dataset.s] = a; });
document.querySelectorAll('#spbody section').forEach(function (sec) {
  new IntersectionObserver(function (es) {
    es.forEach(function (e) {
      if (e.isIntersecting) {
        links.forEach(function (a) { a.classList.remove('on'); });
        map[e.target.id].classList.add('on');
      }
    });
  }, { root: body, rootMargin: '-20% 0px -70% 0px' }).observe(sec);
});
links.forEach(function (a) {
  a.addEventListener('click', function (e) {
    e.preventDefault();
    document.getElementById(a.dataset.s).scrollIntoView({ behavior: 'smooth' });
  });
});
</script>
本节要点滚动高亮 = IntersectionObserver + rootMargin 微调;点击导航用 scrollIntoView 平滑滚。
🔗 相关词条事件DOMCSS 特效