文章

Astro 内容站:布局组件拆分,建立 BaseLayout、SitePage 与全局样式层

把页面骨架、站点级 props 和全局样式从页面实现里抽出,为 Header、主题和滚动恢复提供稳定挂载点。

更新说明(2026-04-16):站点已经移除了这套自定义 ScrollRestore。它会在真实刷新里制造明显的重影和跳帧;当前实现改成了更简单的策略:刷新时一律回到页首,不再尝试恢复中段阅读位置。

站点只有首页和文章页时,把所有东西都塞进 BaseLayout.astro 还能忍。等页面开始变多,问题就出来了:

  • 页面骨架、全局样式、头部结构、主题脚本、滚动脚本挤在一个文件里
  • 中英切换和站点级文案需要在很多页面重复传递
  • 以后再加归档、系列、移动端导航时,很难判断该改哪里

当前仓库的做法,是先把布局层拆出清楚的装配边界。

最终分层

和布局直接相关的文件现在是这些:

  • src/layouts/BaseLayout.astro
  • src/components/layout/SitePage.astro
  • src/components/layout/LayoutStyles.astro
  • src/components/layout/SiteHeader.astro
  • src/components/layout/ThemeController.astro
  • src/components/layout/ScrollRestore.astro

其中真正负责“骨架”的只有前 3 个,另外 3 个是被挂进去的行为或结构组件。

BaseLayout 只负责装配

当前版本的 BaseLayout.astro 不再承载具体交互,只做三件事:

  1. 输出 <html> / <head> / <body> 的页面骨架
  2. 接收站点级 props
  3. 把主题、滚动恢复、全局样式和 Header 挂进去

核心结构如下:

---
import LayoutStyles from "../components/layout/LayoutStyles.astro";
import ScrollRestore from "../components/layout/ScrollRestore.astro";
import SiteHeader from "../components/layout/SiteHeader.astro";
import ThemeController from "../components/layout/ThemeController.astro";
---

<html lang={lang} data-theme="light">
  <head>
    <ThemeController />
    {scrollRestore ? <ScrollRestore /> : null}
    <LayoutStyles />
  </head>
  <body>
    <SiteHeader ... />
    <main>
      <slot />
    </main>
  </body>
</html>

这样拆完以后,布局文件就变成一个稳定的装配点,而不是一份越来越长的杂糅脚本。

SitePage 负责站点级上下文

页面层再往上一层,当前项目又做了一个 SitePage.astro。它的作用不是新增视觉层,而是把每个页面都会重复做的那套事情收起来:

  • 根据 locale 读取 site.ts 里的文案
  • 计算当前页面的跨语言跳转地址
  • siteNamelang、导航、切换按钮文案一起传给 BaseLayout

这个组件让 src/pages/*.astro 可以保持很薄。页面文件只需要决定当前是哪一种 page view,不需要再手工拼一遍头部配置。

LayoutStyles 独立承担全局样式

LayoutStyles.astro 是当前站点的全局视觉底板,主要包含:

  • 颜色变量和主题变量
  • body 版心
  • main 正文排版
  • 表格、代码块、图片、引用块等通用内容样式
  • Header 的响应式样式

几个关键点都放在这里:

html {
  background: var(--page-bg);
  scrollbar-gutter: stable;
}

body {
  max-width: 800px;
  margin: 0 auto;
  padding: 40px 20px;
}

main {
  display: grid;
  gap: 1.5rem;
  overflow-wrap: break-word;
}

这层抽出来以后,页面组件就不需要各自维护一份排版规则,新增页面也会自动落到统一视觉体系里。

为什么先做这一步

因为后面的几个功能都依赖它:

  • ThemeController 需要一个稳定的 <html data-theme> 挂点
  • ScrollRestore 需要在 <head> 提前执行
  • SiteHeader 需要统一被所有页面复用
  • 首页、文章页、系列页、归档页都需要共享相同的正文排版和版心

如果不先把布局层分清,后面每加一个功能,都会重新把 BaseLayout.astro 拉回到“大文件加内联逻辑”的状态。

当前这一步解决的其实不是视觉,而是维护性

拆完之后,职责边界就很明确:

  • BaseLayout 是页面骨架
  • SitePage 是站点级页面包装器
  • LayoutStyles 是全局样式层

至于 Header、主题切换和滚动恢复,则各自进入独立组件和独立页面。这样站点从最初的“能跑”继续往上长时,不会再因为布局文件过重而卡住。

相关文章

Astro 内容站:PageHero 组件与页面头部统一

把列表页、首页、系列页和详情页里重复的标题区抽成 PageHero,让返回链接、eyebrow、标题和状态文案共用一套骨架。

2026-04-16

Astro 内容站:PageSectionHeader 组件与区块标题复用

把 section 标题、补充说明、右侧动作和分组计数统一到一个组件里,让首页、归档和索引列表共享稳定的区块头结构。

2026-04-16

Astro 内容站:组件组合重构、重复代码清理与文档同步

一次收口页面骨架、分页辅助、概览卡和旧文档漂移,把页面组合整理成更稳定的单组件文件结构。

2026-04-16

Astro 内容站:SummaryStatGrid 组件与归档总览卡

把归档页里重复的统计卡结构抽成 SummaryStatGrid,为总条目、文章数、章节数和最近更新时间提供统一的数值卡组件。

2026-04-16