页面显示 Home → AI Tools → ChatGPT issues。Rich Results Test 说 BreadcrumbList 有效。但 Search Console 的 Breadcrumbs 报告报警告或错误,或者 SERP 里的面包屑看起来不对、干脆没了。动手改之前,先把问题分成两种完全不同的情况,因为它们的处理方向正好相反:
- SERP 里的面包屑短了 / 没了,但 Search Console 是干净的。 多半你这边没毛病。从 2025 年 1 月起,Google 在手机搜索结果里不再显示面包屑(只显示域名),桌面端仍然显示。见下文手机端这一节。
- Search Console 的 Breadcrumbs 报告里有 Error 或 Warning 项。 这是你这边的标记问题,确实会影响展示资格。直接跳到修标记。
底层的经典原因是:JSON-LD 与可见 UI 是各自独立生成的——数据源不同、标签规则不同、locale 处理不同。Google 真正的规则(见结构化数据政策)并不是”跟 UI 一字不差”,而是不要标记页面上读者看不到的内容、不要误导。所以目标是对齐,不是逐像素吻合:BreadcrumbList 里的名称和链接必须反映页面上真实存在的路径。
你属于哪一类
| 现象 | 可能原因 | 去哪看 |
|---|---|---|
| 手机上面包屑没了、桌面正常 | 2025 年 1 月的手机端改动,不是你的标记问题 | 手机端 |
Search Console:Either "name" or "item.name" should be specified | 某个列表项缺 name | 具名报错 |
Search Console:Missing field "item" (in "itemListElement") | 非叶子项没有 item URL | 具名报错 |
Search Console:Missing field "id" (in "itemListElement.item") | 有两项 URL 相同 | 具名报错 |
UI 写 “AI Tools”、JSON-LD 写 ai-tools | 该用展示名的地方用了 slug | 原因 1 |
| 本地化页面的 schema 里是英文标签 | JSON-LD 没翻译 | 原因 4 |
| JSON-LD 比页面多几层 | 为”SEO”加的幻影层 | 原因 5 |
SERP 面包屑没了或变短了,但 Search Console 是干净的
这是 2026 年 6 月最常见的虚惊一场。2025 年 1 月 Google 宣布,在所有语言和地区的手机搜索摘要里不再显示面包屑,只显示域名。桌面摘要不变,仍然显示完整路径。这一改动现已写进官方面包屑文档,其功能可用性那行写的是 “available on desktop in all regions and languages where Google Search is available”——并未列出手机端。
所以如果你用手机查,看到的只是 aitoolsguidebook.com,而以前是 aitoolsguidebook.com › AI Tools › ChatGPT issues,这是预期行为,不是标记 bug。无需修改、无需任何操作——Google 仍然会读取并使用这份标记,桌面 SERP 和 Breadcrumbs 报告都不受影响。换到桌面端搜同一个词确认即可。
Search Console 的 Breadcrumbs 报告也可能延迟几天。如果你的源码标记是对的,先相信源码,让报告慢慢追上。
具名的 Search Console 报错及含义
下面这些消息才是真正让页面失去面包屑富媒体资格的,每条都对应一个具体修法。
Either "name" or "item.name" should be specified (in "itemListElement")——某个ListItem没有可读名称。给每一项都加上name字符串(如果用嵌套对象写法,就给item.name)。Missing field "item" (in "itemListElement")——非最后一项缺目标 URL。除最后的叶子项外,每一项都需要item(绝对 URL)。叶子项可以省略item;按 Google 文档,省略时 “Google uses the URL of the containing page”(用所在页面的 URL)。如果这个错误报在你以为的叶子项上,多半是你的position编号有误,Google 因此认为是某个中间项缺了item。Missing field "id" (in "itemListElement.item")——通常是因为有两个列表项指向同一个 URL,Google 把 URL 当作 item 的 id,于是看到重复。把各非叶子项的 URL 改成唯一的,或给嵌套的item对象一个独立的@id。
可以一眼核对的硬性要求(依据 Google 的面包屑文档,2026 年 6 月):至少两个 ListItem;每一项都要有 name(展示给用户看的标题);position 是整数,position 1 表示起点、逐项加 1;item 是该面包屑目标的 URL(用绝对地址);整条路径要反映用户到达该页的典型路径(不要捏造一个不存在的层级)。
常见的对齐类原因
按命中率从高到低。
1. JSON-LD 用 slug 但 UI 用展示名
{ "name": "ai-tools", "item": "https://site.com/category/ai-tools/" }
可见 UI 显示 “AI Tools”(大写、带空格),JSON-LD 的 name 写的是 ai-tools(原始 slug)。这是典型的”标记了页面上看不到的内容”违规。
怎么判断:把可见标签和 JSON-LD name 一个字一个字地对。大小写算、空格也算。
2. URL 大小写或尾斜杠差异
JSON-LD:https://site.com/Category/AI-Tools。可见锚点:https://site.com/category/ai-tools/。逻辑目标相同、字符串不同——而且如果 canonical 版本和路径里那个不一致,还可能造成软重复。
怎么判断:逐条把锚点的 href 跟对应的 JSON-LD item 比。两者应该解析到同一个 canonical URL(大小写一致、尾斜杠策略一致)。
3. UI 省略首页、JSON-LD 包含(或反过来)
UI 显示 “AI Tools → ChatGPT issues”(无 Home),JSON-LD 位置 1 是 Home,或者反过来。如果是有意且前后一致的选择,没问题;但意外的两层不一致,通常说明两个生成器对不上。
怎么判断:数可见面包屑项数 vs. itemListElement.length。若无意中不相等,就是两条代码路径在飘。
4. 本地化页面发的是英文 JSON-LD
非英文页面 UI 显示翻译后的标签(“首页 → AI 工具”),但 JSON-LD 仍写英文原文(“Home → AI Tools”)。这样 schema 描述的就是页面上没有的内容。
怎么判断:打开一个非默认语言的 URL,对比 JSON-LD name 字段和可见标签。
5. 为”SEO”加的幻影层
有人加了只存在于标记里的中间层(Home → AI → Tools → AI Tools → ChatGPT),以为能加分。页面实际显示的层更少。这正是 Google 政策禁止的”误导 / 不可见”情形,会压制富媒体结果。
怎么判断:数 JSON-LD 的位置数。如果超过可见路径(加上叶子)的数量,就是有幻影层,删掉。
一个合法的例外:当确实有多条真实导航路径通向同一页面时,Google 明确允许一个页面上有多个
BreadcrumbList对象(数组形式)。这跟往一条路径里塞假层不同——每个列表都必须描述一条真实路径。
最快的修法
最稳的修法是:把面包屑只算一次,让可见 UI 和 JSON-LD 都从这一个数组渲染。这样两者就不可能再飘。
第 1 步:对单页面把两层 diff 出来
# 可见面包屑的锚文本和 href
curl -s "https://site.com/article/" | grep -oP '<nav[^>]*aria-label="breadcrumb[^>]*>[\s\S]+?</nav>'
# JSON-LD 面包屑块
curl -s "https://site.com/article/" | grep -oP '"@type":\s*"BreadcrumbList[\s\S]+?</script>'
逐位置对比。哪一项的 name 或 canonical URL 不一样,bug 就在那。
第 2 步:两层从同一个源生成
---
const breadcrumb = [
{ name: 'Home', url: '/' },
{ name: 'AI Tools', url: '/category/ai-tools/' },
{ name: article.title, url: Astro.url.pathname },
];
const jsonLd = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": breadcrumb.map((b, i) => ({
"@type": "ListItem",
"position": i + 1,
"name": b.name,
// 按 Google 规范,叶子项省略 `item`,让最后一位没有链接
...(i < breadcrumb.length - 1
? { "item": new URL(b.url, Astro.site).toString() }
: {}),
})),
};
---
<nav aria-label="breadcrumb">
<ol>
{breadcrumb.map((b, i) => (
<li>
{i < breadcrumb.length - 1
? <a href={b.url}>{b.name}</a>
: <span>{b.name}</span>}
</li>
))}
</ol>
</nav>
<script type="application/ld+json" set:html={JSON.stringify(jsonLd)}></script>
一个 breadcrumb 数组驱动两种表示,于是 name 一定一致,叶子项也正确地不带 item。
第 3 步:在源头本地化
const breadcrumb = [
{ name: t('breadcrumb.home'), url: lang === 'en' ? '/' : `/${lang}/` },
{ name: t(`category.${article.category}`), url: `/${lang}/category/${article.category}/` },
{ name: article.title, url: Astro.url.pathname },
];
因为两层都读同一个 breadcrumb 数组,标签翻译一次,UI 和 JSON-LD 一起改好。
第 4 步:加 CI 守卫(子集检查,不是逐字相等)
现在用严格的逐字相等断言太脆——它会误杀”可见路径精简、schema 路径更全”这种合法模式,也会误杀多个 BreadcrumbList 的情况。改成断言每个 JSON-LD name 都出现在可见面包屑里,这样能抓出 slug、未翻译标签、幻影层,又不会误报:
// scripts/check-breadcrumb.mjs
import fs from 'node:fs';
import { parse } from 'node-html-parser';
for (const file of getDistHtmlFiles()) {
const root = parse(fs.readFileSync(file, 'utf8'));
const visible = new Set(
root.querySelectorAll('nav[aria-label="breadcrumb"] a, nav[aria-label="breadcrumb"] span')
.map(el => el.text.trim())
);
for (const script of root.querySelectorAll('script[type="application/ld+json"]')) {
let data;
try { data = JSON.parse(script.text); } catch { continue; }
for (const node of [].concat(data)) {
if (node['@type'] !== 'BreadcrumbList') continue;
for (const item of node.itemListElement) {
const name = item.name ?? item.item?.name;
if (name && !visible.has(name)) {
console.error(`MISMATCH in ${file}: JSON-LD "${name}" not in visible breadcrumb`);
}
}
}
}
}
第 5 步:校验并重新提交
把修好的 URL 放进 Rich Results Test——它只显示 Google 能展示的功能,所以判断面包屑资格用它最对(要做完整 schema.org 规范检查再用 Schema Markup Validator)。然后在 Search Console 对代表性页面跑 URL Inspection → Test live URL,再点 Request indexing。Breadcrumbs 报告通常 1–2 周刷新一次;有效项会在下次重新抓取后退出 Error/Warning 状态。
怎么确认修好了
- Rich Results Test 报告该页符合 Breadcrumbs 资格、零错误,且预览里的名称跟你的可见路径一致。
- 每个
ListItem的name都能在页面可见面包屑里找到。 - URL Inspection 的渲染 HTML 里显示的
BreadcrumbList跟你发布的一致(排除 CDN 或边缘转换把它剥掉的情况)。 - 下次重新抓取后,Search Console Breadcrumbs 报告里该 URL 进入 Valid,无 Error/Warning 项。
预防建议
- 可见面包屑和 JSON-LD 用同一个 helper 生成。
- 双语站两层都读同一翻译源。
itemURL 用绝对地址且 canonical(大小写、尾斜杠策略一致)。- 不要为 SEO 往单条路径里塞幻影层;若确实需要多条真实路径,改成输出多个
BreadcrumbList对象。 - 改 URL 结构时同时重新生成两层——绝不手动 patch JSON-LD。
FAQ
- 手机搜索结果里的面包屑不见了,是我搞坏了吗? 不是。从 2025 年 1 月起 Google 在手机摘要里隐藏面包屑、只显示域名。桌面端仍显示完整路径,标记照样被读取。无需修改。
- 可以省略首页吗? 可以,是允许的。只要 UI 和 JSON-LD 保持一致即可;真正的问题是两层之间意外不一致。
- 最后一项要链到当前页吗? 按 Google 规范,最后的叶子项可以省略
item;省略时 Google 会用所在页面的 URL 作为这一位置。给叶子项加上item也接受。两种写法都行——全站统一一种约定即可。 - Breadcrumbs 报告显示没有展示量、像是空的,是坏了吗? 多半不是。自 2025 年 1 月的手机端改动后,面包屑只在桌面端渲染,所以和可见功能挂钩的展示类指标自然下来了。该报告仍然在跟踪标记是否有效(Valid / Warning / Error),这才是你该盯的;Google 照样会读取并使用这份标记。
- Rich Results Test 过了,但 Search Console 还报警告——以谁为准? 两者都可能对。测试反映当前源码;报告反映上次抓取,可能延迟几天。修源码、跑 live 测试、请求收录,让报告追上即可。
- 我的可见面包屑比 schema 路径更简,这算违规吗? 不一定。Google 禁止的是标记页面上看不到的内容;但”可见路径更短、背后有一条更全且真实的 schema 路径”是允许的。别捏造不存在的导航层级就行。