2733 字
14 分钟

组件库写博客:更优雅的写博客方案

本文提到的组件库是我维护的 March7th UI:一套零依赖 Web Components UI 组件库,适合个人博客、作品集和文档内容增强。组件文档与在线演示地址:https://ui.march7th.online/

以前写博客,Markdown 负责内容表达已经足够舒服:标题、列表、引用、代码块、图片都很自然。

但一旦文章需要更丰富的表达,比如提示卡片、步骤条、数据卡片、折叠面板、标签页、进度条,纯 Markdown 就开始显得不够用了。继续用 HTML 手写样式会让正文变脏;每篇文章复制一段 CSS 也不好维护;如果把所有内容都改成框架组件,又会让写作成本变高。

所以这次我把自己的 UI 组件库 @mar7th/march7th-ui 接入到了博客正文阅读页。组件库的完整文档和在线演示可以在 March7th UI 查看,里面整理了按钮、表单、通知、卡片、时间线、轮播等适合博客和作品集使用的组件。

现在写文章时,可以直接在 .md.mdx 中写:

<m7-button type="primary">开始阅读</m7-button>
<m7-notice type="tip" title="提示">这里是一段提示内容。</m7-notice>

浏览器加载文章页后,这些标签会自动升级为真正的交互组件。

为什么选择 Web Components#

March7th UI 是一套基于 Web Components 的组件库。它最大的好处是:组件本身就是浏览器原生自定义标签,不依赖 Vue、React、Svelte 这类运行时。

如果你也在写个人博客、项目文档或作品集页面,可以直接访问 https://ui.march7th.online/ 预览组件效果和使用方式。

这点非常适合博客正文:

  • Markdown 可以保留原始 HTML,自定义标签能直接写进正文。
  • MDX 也可以使用小写短横线标签,例如 <m7-button>,不需要额外 import。
  • 组件和博客框架解耦,之后博客换技术栈,正文里的 m7 标签仍然有机会继续复用。
  • UI 风格集中在组件库维护,不需要每篇文章单独写一堆样式。
  • 对读者来说,文章表达更丰富;对作者来说,写作仍然接近 Markdown。
用 Markdown 写内容,用 Web Components 补足表达能力。文章仍然是文章,只是在必要的位置插入组件。

整体方案#

这次接入没有把组件库作为 npm 依赖打进博客构建产物,而是使用 unpkg CDN 加载已经发布的 npm 包。

整体结构很简单:

具体来说:

  1. @mar7th/march7th-ui 已经发布到 npm。
  2. 在博客项目里新增一个 M7Components.astro
  3. 这个组件负责从 unpkg 加载 m7 的 CSS 和 JS。
  4. 只在博客正文页,也就是 post 阅读页的 <head> 中引入它。
  5. Markdown 或 MDX 正文里直接写 <m7-*> 标签。

这样的好处是接入边界非常清晰:只有文章页会加载组件库资源,列表页、关于页、归档页不受影响。

接入代码#

第一步,新增一个专门加载 March7th UI 的 Astro 组件。

---
import { siteConfig } from "@/config/siteConfig";
const packageName = "@mar7th/march7th-ui";
const packageVersion = "1.1.2";
const cdnBase = `https://unpkg.com/${packageName}@${packageVersion}`;
const defaultHue = siteConfig.themeColor.hue;
const defaultMode = siteConfig.themeColor.defaultMode ?? "light";
---
<link rel="preconnect" href="https://unpkg.com" crossorigin />
<link rel="stylesheet" href={`${cdnBase}/dist/march7th-tokens.css`} />
<link rel="stylesheet" href={`${cdnBase}/dist/march7th-ui.css`} />
<script is:inline define:vars={{ defaultHue, defaultMode }}>
// 这里同步博客现有主题状态到 m7 变量:
// dark -> m7-dark
// --hue -> --m7-hue
// 同时提供 window.March7thTheme,兼容 m7-theme-switch / m7-hue-picker。
</script>
<script is:inline src={`${cdnBase}/dist/march7th-ui.bundle.min.js`} defer></script>

这里固定了版本号 1.1.2,这是有意为之。组件库升级后,可以手动改版本并验证,避免 unpkg 默认 latest 变动导致线上文章样式突然变化。

第二步,在文章页引入这个加载组件。

---
import M7Components from "@components/misc/M7Components.astro";
---
<MainGridLayout
banner={processedImage}
title={entry.data.title}
description={entry.data.description}
lang={entry.data.lang}
setOGTypeArticle={true}
postSlug={entry.slug}
headings={headings}
>
<M7Components slot="head" />
<Markdown class="mb-6 markdown-content onload-animation">
<Content />
</Markdown>
</MainGridLayout>

这一步完成后,文章正文里的 m7 标签就可以正常工作。

主题同步#

博客本身已经有亮色、暗色和主题色 hue 配置。March7th UI 也有自己的设计变量,例如:

:root {
--m7-hue: 215;
}
:root.m7-dark {
color-scheme: dark;
}

所以接入时不能只加载组件脚本,还需要把博客已有的主题状态同步过去。

关键动作有三个:

const root = document.documentElement;
root.classList.toggle("m7-dark", root.classList.contains("dark"));
root.style.setProperty("--m7-hue", getComputedStyle(root).getPropertyValue("--hue"));
root.setAttribute("data-m7-resolved-mode", root.classList.contains("dark") ? "dark" : "light");

这样 m7 组件就会跟随博客现有的亮暗模式和主题色变化,不会出现正文是暗色、组件仍然是亮色的割裂感。

这里还有一个很重要的前提:当前博客和 March7th UI 的设计语言本来就是同源的。它们使用相近的圆角、间距、色彩、卡片层级和交互动效,所以把组件放进正文后,整体观感会比较自然,不像是突然嵌入了一套外来的 UI。

如果在其它博客或文档站中接入,就需要额外考虑页面风格是否一致。组件库能解决“组件能力”和“基础设计规范”的问题,但不能自动保证它和任何站点都完全匹配。实际使用时,最好先检查页面的主色、背景、字号、圆角、阴影、暗色模式等基础风格,再决定是直接使用默认主题,还是做一层变量覆盖。

March7th UI 的样式主要通过 CSS 变量组织,因此可以按站点风格覆盖核心变量:

:root {
--m7-hue: 250;
--m7-radius-large: 0.75rem;
--m7-card-bg: #ffffff;
--m7-btn-regular-bg: oklch(0.95 0.025 var(--m7-hue));
}
:root.m7-dark {
--m7-card-bg: oklch(0.23 0.015 var(--m7-hue));
--m7-btn-regular-bg: oklch(0.33 0.035 var(--m7-hue));
}

也就是说,最理想的接入方式不是简单地“把组件塞进文章”,而是让组件库的变量和站点已有设计系统对齐。这样组件增强的是内容表达,而不是打断页面风格。

在 Markdown 中怎么写#

最简单的方式就是把 m7 组件当作 HTML 标签写进正文。

<m7-notice type="tip" title="写作提示">
这是一段写在 Markdown 中的 m7 通知组件。
</m7-notice>
<m7-button type="primary">主要按钮</m7-button>

也可以用普通 HTML 容器组合多个组件:

<div class="m7-stack">
<m7-input label="文章标题" placeholder="输入标题"></m7-input>
<m7-textarea label="文章摘要" placeholder="输入摘要" rows="4"></m7-textarea>
</div>

如果只是使用 m7 组件,普通 .md 已经足够。只有在你需要 import 框架组件、写 JSX 表达式、组合更复杂的运行时代码时,才需要换成 .mdx

效果演示#

下面这些不是截图,而是直接写在这篇 Markdown 里的真实组件。

按钮和徽章#

发布文章 保存草稿 预览 查看组件库
Markdown Web Components unpkg

提示卡片#

对教程类文章来说,提示、注意、警告、步骤和状态说明都很常见。用组件表达这些内容,比只用引用块更清晰。 组件应该服务于内容表达,而不是把文章变成展示页。正文还是要以清晰的文字、结构和代码为主。

标签页#

适合日常博客、教程、笔记和长文。写作成本最低,版本管理也最自然。
适合需要混入框架组件或运行时代码的文章。能力更强,但写作复杂度也更高。
适合在 Markdown 中补充交互表达。写法接近 HTML,维护成本集中在组件库。

折叠面板#

手写 HTML 和 CSS 可以实现效果,但很容易让文章正文变得冗长,也不利于统一维护。组件库能把样式和交互沉淀下来。
MDX 很强,但每篇文章都引入组件会增加心智负担。Web Components 的优势是直接以标签形式出现在内容里,更接近写 HTML。

时间线#

数据卡片#

这个方案的优点#

我认为这个方案最舒服的地方,是它没有破坏 Markdown 的写作体验。

总结下来有几个优点:

  1. 写作仍然轻量:大多数内容继续用 Markdown,只有需要增强表达时才插入 m7 标签。
  2. 组件统一维护:样式、交互、主题都在 @mar7th/march7th-ui 中维护,文章不承担 UI 细节。
  3. 接入范围可控:只在 post 页面加载资源,不影响其它页面。
  4. 跨框架友好:Web Components 不绑定具体前端框架。
  5. 适合文档型内容:教程、组件文档、项目说明、更新日志都可以写得更清晰。
  6. 版本可锁定:unpkg 路径带上 npm 版本号,升级节奏由自己控制。

需要注意的问题#

这个方案也不是完全没有取舍。

首先,CDN 资源依赖网络。如果希望完全自托管,可以把 dist/march7th-ui.bundle.min.js 和 CSS 放到博客的 public 目录,再改成本地路径。

其次,全量 bundle 会加载全部组件。如果文章长期只用少数组件,可以后续做按需构建,把常用组件打成一个更小的 custom bundle。

再次,页面风格需要评估。我的博客和 March7th UI 的设计本来同源,所以接入后视觉一致性比较高;换到其它站点时,不一定可以直接无脑套用。建议至少覆盖 --m7-hue、背景色、文本色、圆角和卡片颜色,让组件看起来像页面的一部分。

最后,文章里不要过度组件化。组件是为了让重点更清楚,而不是为了炫技。真正重要的仍然是内容结构、解释质量和代码示例。

后续计划#

后面可以继续做几件事:

  • 整理一篇 m7 组件写作速查表。
  • 为常用组件补充更适合博客场景的属性。
  • 做一个按需构建版本,只给文章页加载文档常用组件。
  • 把更多 Markdown 扩展能力沉淀成稳定写作规范。
对个人博客来说,Markdown 负责内容,组件库负责表达增强,是一个很自然的分工。写文章不必变成写页面,但文章也不必永远停留在纯文本。

参考#

组件库写博客:更优雅的写博客方案
https://march7th.online/blog/posts/0034-组件库写博客-更优雅的写博客方案/
作者
Yiguo
发布于
2026-06-30
许可协议
CC BY-NC-SA 4.0
最后更新于 2026-07-01
所属合集

组件库写博客

用 March7th UI 增强 Markdown 博客写作体验,把组件能力沉淀到文章内容中。

查看完整合集

目录