分类与标签页可以是站内链接最强的节点,也可以是最大的薄页负担。技术做法一样,关键看你在上面放了多少真内容。
问题背景
Astro 用 getStaticPaths + content collection 做分类/标签页很简单,技术上一下午搞定。难的是策略——确保这些页面有足够内容能排名。一个只有 4 篇文章列表、没介绍的分类页,就是个待爆的 soft 404。
判断标准
- 已有 30+ 篇,需要浏览页帮读者整理。
- 希望 hub 页面能排短尾词。
- 预期读者会在 Google 入口页之外继续探索。
- 每个 hub 能写 200-300 字的介绍。
快速结论
分类页当成完整内容页来做——有介绍、有列表、有 FAQ。标签页做精简,长期还薄就 noindex。
实操步骤
- 在
src/content/config.ts里给 articles 加category和tags:
import { defineCollection, z } from 'astro:content';
const articles = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string().min(120).max(160),
category: z.enum(['indie-dev', 'ai-tools', 'prompt-library']),
tags: z.array(z.string()).default([]),
publishedAt: z.date(),
draft: z.boolean().default(false),
}),
});
const categories = defineCollection({
type: 'data',
schema: z.object({
slug: z.string(),
title: z.string(),
intro: z.string().min(200), // 强制写真介绍,不许一行了事
faq: z.array(z.object({ q: z.string(), a: z.string() })).default([]),
}),
});
export const collections = { articles, categories };
- 用
getStaticPaths在src/pages/[category]/index.astro生成分类索引页:
---
import { getCollection, getEntry } from 'astro:content';
import { paginate } from 'astro:paginate';
export async function getStaticPaths({ paginate }) {
const allArticles = await getCollection('articles', e => !e.data.draft);
const categories = await getCollection('categories');
return categories.flatMap(cat => {
const list = allArticles.filter(a => a.data.category === cat.data.slug);
return paginate(list, {
params: { category: cat.data.slug },
props: { meta: cat.data },
pageSize: 24,
});
});
}
const { page, meta } = Astro.props;
---
<html>
<head>
<title>{meta.title}</title>
<link rel="canonical" href={`https://yourdomain.com/${meta.slug}/`} />
</head>
<body>
<h1>{meta.title}</h1>
<p>{meta.intro}</p>
<ul>
{page.data.map(a => (
<li><a href={`/articles/${a.slug}/`}>{a.data.title}</a></li>
))}
</ul>
{page.url.prev && <a href={page.url.prev}>上一页</a>}
{page.url.next && <a href={page.url.next}>下一页</a>}
</body>
</html>
- 每个分类写 200-300 字真介绍,存成
src/content/categories/下的 JSON / YAML:
# src/content/categories/indie-dev.yaml
slug: indie-dev
title: Indie Dev — 一个人做、上线、做收入
intro: >
写给独立开发者的实战文章,覆盖大部分教程跳过的部分:
域名决策、托管平台权衡、App Store 提审的坑、变现、
以及对月访问量在 1 万以下的站点真正有效的 SEO 工作。…
faq:
- q: 第一个站要做双语吗
a: 只在你能长期维护两种语言的前提下。
- 标签页放
src/pages/tags/[tag].astro,做精简;按数量动态加robotsmeta:
---
const articlesWithTag = (await getCollection('articles'))
.filter(a => a.data.tags.includes(tag));
const shouldNoindex = articlesWithTag.length < 5;
---
<head>
{shouldNoindex && <meta name="robots" content="noindex,follow" />}
<link rel="canonical" href={`https://yourdomain.com/tags/${tag}/`} />
</head>
-
渲染顺序:介绍 → 文章列表 → FAQ → 相关分类。每一块都加 Google 能看到的份量。
-
构建后数生成页面,抓”标签爆炸”问题:
npm run build
find dist/tags -name 'index.html' | wc -l
# 超过 200 就是标签爆炸
- 决定 noindex 策略:分类保持可收录;标签页文章不到 5 篇就 noindex。
容易踩的坑
- 分类页只放列表没介绍——Google 直接当薄页。
- 从每篇文章的关键词自动生成标签,最后几百个空标签页。
- 忘做分页,一个分类一页 200 篇,CWV 跪。
- 同一文章同时挂多个分类却没处理 canonical,出现重复。
- 把分类名硬编码在 URL 里,改名就死链。
这篇适合谁
30+ 篇规模、想做分类页 SEO 和读者留存的 Astro 内容站。
这篇不适合谁
一个时间线列表就够的小博客。
FAQ
- 标签页要 noindex 吗: 2026 年默认建议 noindex,除非你给标签页写真内容。空标签页纯 SEO 负担。
- 分类页能排短尾词吗: 能,但必须有真正的介绍内容和从文章反链到分类的强内链。
- 长分类怎么分页: 用 Astro 的
paginateAPI,每页 20-30 条,加 prev/next 和自指 canonical。 - 标签和分类区别是什么: 分类稳定、数量少,定义结构;标签流动、数量多,只有读者需要横切时才用。
相关阅读
标签: #独立开发 #Astro #Content Collections #SEO #Pillar / Cluster