修复文档和博客页面侧边栏滚动问题
解决文档页左侧导航、右侧目录以及博客详情页目录在页面滚动时跟随正文移动的问题,通过精准计算 CSS sticky top 值与 display: contents 布局扁平化消除视觉偏移。
问题描述
BDI 官网的文档页面和博客详情页存在侧边栏滚动异常的问题:
- 文档页左侧导航在正文滚动时会向上移动约 32px 后才固定
- 文档页右侧目录嵌套在内容区域的 flex 容器中,sticky 定位受嵌套层级影响
- **博客详情页的"本页目录"**会随正文滚动,且固定位置在页面顶部导航栏后方,导致目录标题不可见
根因分析
CSS Sticky 的工作机制
position: sticky 的行为是:元素在正常文档流中渲染,当滚动使元素距离视口顶部达到 top 阈值时,元素"粘住"不再移动。
关键公式:
滚动距离 = 初始位置 − sticky top 值
如果 sticky top 值 小于 元素的初始位置,元素会先向上滚动一段距离再固定。
文档页右侧目录的嵌套问题
文档页的关键困难在于右侧目录嵌套层级过深。布局结构如下:
| 层级 | 元素 | 说明 |
|---|---|---|
| 1 | 外层 flex | layout.tsx 的主容器 |
| 2 | 左侧 aside | 与外层 flex 同级,sticky 直接生效 |
| 2 | content-div | 包裹 page.tsx 输出的容器 |
| 3 | 内层 flex | page.tsx 的 flex 容器 |
| 4 | 右侧 aside | 嵌套在 content-div 和内层 flex 之中 |
左侧导航栏是外层 flex 的直接子元素,sticky 行为直接有效;而右侧目录嵌套了两层包装 div,可能在嵌套布局中出现微妙的定位偏差。
博客页的具体问题
| 项目 | 值 |
|---|---|
| 原 sticky top 值 | top-8 = 2rem = 32px |
| 页面顶部导航栏高度 | 64px |
| 结果 | 目录固定在导航栏后方,不可见 |
修复方案
核心原则
移除容器顶部内边距,精确匹配 header 高度设置 sticky top,使用
display: contents扁平化嵌套层级。
文档页修复
涉及文件:
app/[locale]/docs/layout.tsxapp/[locale]/docs/[[...mdxPath]]/page.tsx
核心改动:
- 容器移除顶部内边距,改为
pb-8 lg:pb-12 - 内容区和侧边栏内部各自添加
pt-8 lg:pt-12实现视觉对齐 - sticky top 设为
top-16.25= 65px(headerh-16+border-b1px) - 关键修复:content-div 添加
xl:contents,page.tsx 内层 flex 添加xl:contents
xl:contents 使包装元素在 xl 断点以上(右侧目录可见时)变为 display: contents,其子元素直接成为外层 flex 的子元素,右侧目录与左侧导航处于同一嵌套层级,sticky 行为完全一致。
博客页修复
涉及文件: app/[locale]/blog/[slug]/page.tsx
将原 Grid 布局重构为 Flex 布局:
- TOC 从 Grid 的第二列提升为 Flex 的独立子元素
- sticky top 设为
top-16.25= 65px,与 header 完全匹配 - 移除
self-start,采用内层 div 承载 sticky 行为
SQLite 警告抑制
涉及文件: .npmrc(新建)
构建和开发时 node:sqlite(实验性 API)会输出 ExperimentalWarning。通过在 .npmrc 中设置 node-options=--disable-warning=ExperimentalWarning,利用 Node.js 原生机制在所有进程(包括构建 worker)中统一抑制。
修改文件一览
| 文件 | 修改内容 |
|---|---|
app/[locale]/docs/layout.tsx | 重构 padding,sidebar sticky top,content-div 添加 xl:contents |
app/[locale]/docs/[[...mdxPath]]/page.tsx | TOC sticky top,内层 flex 添加 xl:contents |
app/[locale]/blog/[slug]/page.tsx | Grid 转 Flex 布局,TOC sticky top |
.npmrc | node-options=--disable-warning=ExperimentalWarning |
next.config.ts | 移除 SQLite monkey-patch(改用 .npmrc) |
验证结果
pnpm check通过,72 个文件无需修复pnpm build编译成功,28 个页面生成正常,SQLite 警告消失- 开发服务器终端无 ExperimentalWarning 输出
总结
本次修复的两个核心技术要点:
-
CSS
position: sticky的精确计算:sticky 元素的初始位置必须等于top阈值才能实现零偏移。将top设为top-16.25(= 65px =h-16+border-b),与 header 高度精确匹配。 -
display: contents消除嵌套影响:当 sticky 元素嵌套在多层 flex 容器中时,使用xl:contents在目标断点扁平化 DOM 层级,让右侧目录和左侧导航成为同一 flex 容器的直接子元素,确保 sticky 行为完全一致。
- 版本: 2.0.0
- 时间: 2026-02-19 14:30:00
- 作者: Claude Opus 4.6
- 简介: 第二版修复,重构容器 padding 和布局结构,将 sticky top 精确匹配 header 高度以消除所有视觉偏移