如何为Jekyll Minima主题博客添加侧边跟随式自动ToC?
为Jekyll Minima主题添加侧边跟随式目录(ToC)
方案思路
避开Bootstrap依赖,用原生JavaScript自动提取文章标题生成ToC,配合CSS实现固定跟随效果,同时兼容Minima的深色主题。
具体实现步骤
1. 新建ToC布局组件
在_includes目录下创建toc.html文件,内容如下:
{% if page.toc %} <div class="toc-container"> <h3>目录</h3> <nav class="toc"> <ul id="toc-list"></ul> </nav> </div> {% endif %}
2. 修改文章布局文件
编辑_layouts/post.html,在文章内容区域的合适位置(比如内容右侧)插入ToC组件:
<div class="post-content-wrapper"> {% include toc.html %} <div class="post-content"> {{ content }} </div> </div>
3. 添加自定义CSS
在assets/css/style.scss中追加以下样式(兼容深浅色主题):
.toc-container { position: sticky; top: 2rem; max-height: calc(100vh - 4rem); overflow-y: auto; width: 280px; margin-right: 2rem; padding: 1rem; border-radius: 4px; background: var(--background-color); border: 1px solid var(--border-color); } .post-content-wrapper { display: flex; flex-wrap: wrap; gap: 1rem; } .post-content { flex: 1 1 600px; } .toc ul { list-style: none; padding-left: 1rem; } .toc li { margin: 0.5rem 0; } .toc a { color: var(--link-color); text-decoration: none; } .toc a.active { font-weight: bold; color: var(--accent-color); } /* 移动端适配 */ @media (max-width: 768px) { .toc-container { position: static; width: 100%; margin-right: 0; max-height: none; } } /* 适配Minima主题的深浅色变量 */ @media (prefers-color-scheme: dark) { :root { --background-color: #1a1a1a; --border-color: #333; --link-color: #61dafb; --accent-color: #ffd700; } } @media (prefers-color-scheme: light) { :root { --background-color: #fff; --border-color: #eee; --link-color: #0066cc; --accent-color: #ff4500; } }
4. 添加JavaScript实现自动生成与高亮
在assets/js/toc.js中编写以下代码:
document.addEventListener('DOMContentLoaded', function() { const tocList = document.getElementById('toc-list'); const postContent = document.querySelector('.post-content'); if (!tocList || !postContent) return; // 提取文章中的h2-h4标题 const headings = postContent.querySelectorAll('h2, h3, h4'); if (headings.length === 0) { tocList.parentElement.parentElement.style.display = 'none'; return; } // 生成ToC列表项 headings.forEach(heading => { // 自动为无ID的标题生成ID if (!heading.id) { heading.id = heading.textContent.trim().toLowerCase().replace(/\s+/g, '-'); } const li = document.createElement('li'); const a = document.createElement('a'); a.href = `#${heading.id}`; a.textContent = heading.textContent; li.classList.add(`toc-level-${heading.tagName.toLowerCase()}`); li.appendChild(a); tocList.appendChild(li); }); // 用IntersectionObserver实现滚动时的当前标题高亮 const observerOptions = { root: null, rootMargin: '0px', threshold: 0.1 }; const observer = new IntersectionObserver(function(entries) { entries.forEach(entry => { const tocLink = document.querySelector(`.toc a[href="#${entry.target.id}"]`); if (!tocLink) return; if (entry.isIntersecting) { document.querySelectorAll('.toc a.active').forEach(link => link.classList.remove('active')); tocLink.classList.add('active'); tocLink.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } }); }, observerOptions); headings.forEach(heading => observer.observe(heading)); // 点击ToC项平滑滚动到对应标题 document.querySelectorAll('.toc a').forEach(link => { link.addEventListener('click', function(e) { e.preventDefault(); const targetElement = document.querySelector(this.getAttribute('href')); if (targetElement) { targetElement.scrollIntoView({ behavior: 'smooth' }); } }); }); });
然后在_layouts/post.html末尾引入该JS文件:
<script src="{{ '/assets/js/toc.js' | relative_url }}"></script>
5. 启用ToC
在需要显示目录的文章头部添加toc: true配置:
--- layout: post title: "你的文章标题" date: 2024-05-20 10:00:00 toc: true ---
关键注意事项
- 复用Minima主题自带的颜色变量,避免引入外部样式导致的主题冲突
- 通过
position: sticky实现目录跟随效果,无需监听滚动事件 - 用IntersectionObserver实现滚动高亮,性能优于传统的scroll事件监听
内容的提问来源于stack exchange,提问作者Physicys
相关产品推荐
相关产品推荐

