Github Pages Minima - 右侧悬浮目录
Jekyll Minima模版说明
GitHub Pages 默认模板(通常是 Jekyll 主题)的布局文件,核心逻辑是通过“同名覆盖”机制:只要你在自己的仓库中创建一个与主题源码路径、文件名完全相同的文件夹和文件,GitHub Pages 就会优先使用你的版本。
在 Minima 3.0 主题中实现一个纯 JavaScript 的右侧悬浮目录(TOC),需要考虑到该主题的响应式布局。
Minima 的正文通常居中,左右留有空白,这为悬浮 TOC 提供了理想的展示空间。
_config.xml
GitHub Pages 目前(2025年)运行的是 2.5.x 版本,但 Minima 的主分支已经更新到了 3.0(包含深色模式支持)。
我们通过修改_config.xml更改使用的Minima版本:
remote_theme: jekyll/minima@master
这其实也给以后得构建埋下了隐患,不确定master分支的新代码是否向后兼容,当前没有3.0版本的稳定分支,我们先用master。
https://github.com/jekyll/minima/tree/master
1. 核心代码实现
你可以将以下代码添加到 Jekyll 项目的 _layouts/post.html 文件末尾(在 </article> 之后),或者封装在 _includes/toc.html 中引用。
<div id="floating-toc" class="toc-container">
<div class="toc-title">目录</div>
<nav id="toc-content"></nav>
</div>
<style>
/* 容器样式 */
.toc-container {
position: fixed;
top: 100px;
right: calc(50% - 800px); /* 动态定位在正文右侧 */
width: 300px;
max-height: 70vh;
padding: 15px;
background: #ffffff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
overflow-y: auto;
z-index: 100;
transition: all 0.3s ease;
display: none; /* 初始隐藏,由 JS 根据屏幕宽度显示 */
}
/* 标题样式 */
.toc-title {
font-weight: bold;
font-size: 0.9rem;
color: #2a7ae2; /* Minima 经典蓝色 */
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid #eee;
text-transform: uppercase;
letter-spacing: 1px;
}
/* 导航列表 */
#toc-content ul {
list-style: none;
padding: 0;
margin: 0;
}
#toc-content li {
margin: 5px 0;
line-height: 1.4;
}
#toc-content a {
text-decoration: none;
color: #555;
font-size: 0.85rem;
display: block;
padding: 2px 5px;
border-left: 2px solid transparent;
transition: all 0.2s;
}
/* 悬停与激活状态 */
#toc-content a:hover {
color: #2a7ae2;
background: #f8f9fa;
}
#toc-content a.active {
color: #2a7ae2;
border-left-color: #2a7ae2;
background: #f0f7ff;
font-weight: 500;
}
/* 不同层级的缩进 */
.toc-h2 { padding-left: 15px !important; font-size: 0.8rem !important; }
.toc-h3 { padding-left: 25px !important; font-size: 0.75rem !important; }
/* 响应式:屏幕太小时隐藏目录 */
@media (max-width: 1100px) {
.toc-container { display: none !important; }
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function() {
const postContent = document.querySelector('.post-content');
const tocContent = document.getElementById('toc-content');
const tocContainer = document.getElementById('floating-toc');
if (!postContent || !tocContent) return;
// 1. 提取标题 (h1, h2, h3)
const headings = postContent.querySelectorAll('h1, h2, h3');
if (headings.length < 2) return; // 标题太少则不显示
tocContainer.style.display = 'block';
const ul = document.createElement('ul');
headings.forEach((heading, index) => {
// 确保标题有 ID
if (!heading.id) {
heading.id = 'toc-item-' + index;
}
const li = document.createElement('li');
const a = document.createElement('a');
a.href = '#' + heading.id;
a.textContent = heading.innerText;
a.classList.add('toc-' + heading.tagName.toLowerCase());
// 点击平滑滚动
a.addEventListener('click', (e) => {
e.preventDefault();
heading.scrollIntoView({ behavior: 'smooth' });
});
li.appendChild(a);
ul.appendChild(li);
});
tocContent.appendChild(ul);
// 2. 监听滚动,自动高亮当前章节
const observerOptions = {
root: null,
rootMargin: '0px 0px -80% 0px',
threshold: 0
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
document.querySelectorAll('#toc-content a').forEach(link => {
link.classList.toggle('active', link.getAttribute('href') === '#' + entry.target.id);
});
}
});
}, observerOptions);
headings.forEach(heading => observer.observe(heading));
});
</script>
2. 设计亮点说明
- 配色方案:使用了 Minima 主题默认的蓝色 (
#2a7ae2) 作为主色调,配合淡灰色背景和柔和的阴影,确保视觉上与原主题无缝融合。 - 智能定位:
- 使用
right: calc(50% - 600px)。这能保证在宽屏下,目录始终“挂”在文章内容区的右侧边缘,而不是贴在浏览器最右边。 - 自动隐藏:通过媒体查询,在屏幕宽度小于 1100px 时自动隐藏,避免遮挡正文。
- 使用
- 交互体验:
- 平滑滚动:点击目录项时,页面会顺滑滚动到对应位置。
- 滚动监听 (ScrollSpy):使用
IntersectionObserverAPI,当你阅读文章时,右侧目录会自动高亮对应的章节。
- 纯 JS 实现:不依赖 jQuery,加载速度极快,且自动为没有 ID 的标题生成 ID。
3. 如何调整位置?
如果你的 Minima 主题进行了自定义修改(如改变了正文宽度),你可以调整以下参数:
- 左右间距:修改
.toc-container中的right: calc(50% - 600px)。如果目录离正文太远,就把600px调小;如果重叠了,就调大。 - 上下位置:修改
top: 100px。
目录
目录