如何在滚动页面时高亮固定定位目录的当前阅读位置?
实现固定目录滚动时自动高亮当前章节(优先纯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




