You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在滚动页面时高亮固定定位目录的当前阅读位置?

实现固定目录滚动时自动高亮当前章节(优先纯CSS方案)

嘿,刚好有个简洁的纯CSS方案能满足你的需求——利用CSS的滚动驱动动画(Scroll-Driven Animations)特性,完全不用写JavaScript,就能让固定定位的目录在页面滚动时自动高亮当前视口内的章节。下面一步步拆解实现:

1. 先搭好基础HTML结构

首先得让目录项和页面章节一一对应,每个章节要有唯一的id,目录里的链接href指向对应章节的id,结构大概是这样:

<!-- 固定定位的目录 -->
<nav class="fixed-toc">
  <ul>
    <li><a href="#chapter1">1. 章节1</a></li>
    <li><a href="#chapter1-1">1.1 子章节1</a></li>
    <li><a href="#chapter1-2">1.2 子章节2</a></li>
    <li><a href="#chapter2">2. 章节2</a></li>
  </ul>
</nav>

<!-- 页面主体内容 -->
<main class="content">
  <section id="chapter1">
    <h2>1. 章节1</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipisici elit...</p>
  </section>
  <section id="chapter1-1">
    <h3>1.1 子章节1</h3>
    <p>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua...</p>
  </section>
  <section id="chapter1-2">
    <h3>1.2 子章节2</h3>
    <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris...</p>
  </section>
  <section id="chapter2">
    <h2>2. 章节2</h2>
    <p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore...</p>
  </section>
</main>

2. 用CSS滚动驱动实现自动高亮

核心思路是:给每个章节绑定滚动触发的状态,当章节进入视口范围时,让对应的目录项自动加粗(或变斜体)。直接上代码:

/* 固定目录的基础样式 */
.fixed-toc {
  position: fixed;
  top: 20px;
  left: 20px;
  background: #fff;
  padding: 1rem;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

.fixed-toc ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.fixed-toc li {
  margin: 0.5rem 0;
}

.fixed-toc a {
  text-decoration: none;
  color: #333;
  transition: font-weight 0.2s ease; /* 高亮时的平滑过渡 */
}

/* 定义滚动时间线:基于main元素的滚动行为 */
.content {
  scroll-timeline: --scroll-progress inline;
}

/* 给每个章节添加滚动监听动画 */
section {
  min-height: 100vh; /* 让每个章节至少占一屏,方便测试滚动效果 */
  padding: 2rem;
  /* 关联滚动时间线 */
  animation: track-section linear;
  animation-timeline: --scroll-progress;
  /* 触发高亮的范围:章节进入视口10%时开始,离开视口10%时结束 */
  animation-range: entry 10% cover 10%;
}

/* 关键帧:当章节在视口范围内时,激活高亮变量 */
@keyframes track-section {
  0%, 100% {
    --is-active: 0;
  }
  1%, 99% {
    --is-active: 1;
  }
}

/* 匹配目录链接和对应章节,通过变量控制高亮样式 */
.fixed-toc a[href="#chapter1"] {
  font-weight: calc(400 + (700 - 400) * var(--is-active, 0));
  /* 如果要斜体的话,换成:font-style: calc(normal * (1 - var(--is-active, 0)) + italic * var(--is-active, 0)); */
}
.fixed-toc a[href="#chapter1-1"] {
  font-weight: calc(400 + (700 - 400) * var(--is-active, 0));
}
.fixed-toc a[href="#chapter1-2"] {
  font-weight: calc(400 + (700 - 400) * var(--is-active, 0));
}
.fixed-toc a[href="#chapter2"] {
  font-weight: calc(400 + (700 - 400) * var(--is-active, 0));
}

3. 方案细节说明

  • 完全纯CSS实现,没有任何JS代码,符合你的优先要求。
  • animation-range可以自定义触发时机,比如改成entry 20% cover 20%,就是章节进入视口20%时开始高亮,离开20%时取消,你可以根据阅读习惯调整。
  • 兼容性:目前Chrome 115+、Edge 115+、Safari 16.4+都支持这个特性,如果需要兼容旧浏览器,可以看下面的降级方案。

4. 降级方案(轻量JS,兼容旧浏览器)

如果要支持不兼容滚动驱动动画的浏览器,可以用几行简单的JS监听滚动事件,判断当前视口内的章节,再给目录项加高亮类:

const sections = document.querySelectorAll('section');
const tocLinks = document.querySelectorAll('.fixed-toc a');

window.addEventListener('scroll', () => {
  let currentChapter = '';
  sections.forEach(section => {
    const sectionTop = section.offsetTop;
    const sectionHeight = section.clientHeight;
    // 当滚动位置超过章节顶部减去视口高度的20%时,判定为当前阅读章节
    if (window.pageYOffset >= sectionTop - window.innerHeight * 0.2) {
      currentChapter = section.id;
    }
  });

  // 更新目录高亮状态
  tocLinks.forEach(link => {
    link.classList.remove('active');
    if (link.getAttribute('href') === `#${currentChapter}`) {
      link.classList.add('active');
    }
  });
});

对应的CSS添加高亮样式:

.fixed-toc a.active {
  font-weight: bold;
  /* 斜体的话加:font-style: italic; */
}

这个JS方案代码量极少,兼容性拉满,也符合“尽量简单”的要求。


内容的提问来源于stack exchange,提问作者Suuuehgi

火山引擎 最新活动