Title 标签与 H1 不一致导致 Google 改写

`<title>` 和 `<h1>` 说的不是一件事,Google 哪个都不用 —— 把 SERP 标题改写成正文里裁剪出来的一段。

你的页面 <title>Best Wireless Headphones 2026 | Acme Reviews</title>,可见 <h1> 却是 “We tested 47 pairs of headphones so you don’t have to.”。Google 看到两个互相打架的信号 —— 这页到底是讲什么的?哪个都不用,干脆把 SERP 标题改写成第二段里随便裁出来的一截。点击率往下掉。这是 Google 标题被改写的最常见且最可控的原因之一 —— 跟很多排名问题不同,这个完全在你掌控之内。

常见原因

按频次排序。

1. CMS 里 title 字段和 H1 来源是两个字段

CMS 有 “SEO Title” 和单独的 “Headline” 两个字段。编辑只填 “Headline”,模板用 “SEO Title” 喂 <title>、用 “Headline” 喂 <h1>。从第一天起就漂。

怎么判断:查三篇文章。<title><h1> 很少匹配,就是字段设计的根因。

2. 模板只给 <title> 加品牌后缀

<title> 变成 “How to Bake Sourdough | Acme Cooking”,<h1> 保持 “How to Bake Sourdough”。差距不大,但 Google 把附加到长标题上的品牌后缀视为用户不友好的噪音。

怎么判断<title> 以 ” | Brand” 或 ” - Brand” 结尾;<h1> 没有。

3. H1 是创意 / 标题党,<title> 是 SEO 优化过的

编辑团队写一句有冲击力的 H1 (“Why my sourdough finally stopped collapsing”)。SEO 团队把 title 改成关键词密集的 (“Sourdough Bread Recipe — Step-by-Step Guide”)。两边都是故意写成这样,互不相同。

怎么判断:H1 像博客标题,<title> 像分类页标题。两个独立看都不错;放一起搜索引擎犯糊涂。

4. 页面上有多个 H1

页面 hero 区有 <h1>Category Name</h1>,正文里又有 <h1>Article Title</h1>。Google 不知道哪个是这一页的 H1。

怎么判断:DevTools 里 document.querySelectorAll('h1').length > 1

5. H1 是没有 alt 文本的图片

<h1><img src="/heading.svg"></h1> —— 可见标题是一张 SVG,没 alt。Google 拿不到 H1 的任何文本,只能 fallback 到 <title> —— 如果 <title> 上下文不足,就可能被改写。

怎么判断:view-source 找 <h1>,里面只有空 <img>,没有其他文本内容。

6. H1 在首次渲染后被 JavaScript 动态设置

HTML 响应里 <h1>Loading...</h1>,挂载后 JS 替换掉。Googlebot 抓取并索引的是未渲染的 HTML,<h1> 看起来像是坏的。

怎么判断curl 抓页面看 <h1>。如果是 “Loading…” 或空的,就是动态标题模式在作祟。也可以看 JavaScript 动态设置的标题未被索引

开始前

  • 列出最近 30 天 Google 改写过标题的 10-20 个页面(Search Console → Performance,按展示数过滤,再核对 SERP 实际渲染)。
  • 看改写是否有规律(每次同一模式)还是随机。
  • 记下每个受影响 URL 当前的 <title><h1>
  • 决定策略:H1 跟 <title> 必须完全一致,还是 <title> 是 H1 加品牌后缀。

需要收集的信息

  • 驱动 <title><h1> 的 CMS 字段名。
  • 输出它们的模板代码。
  • 站点是否有给所有 <title> 加品牌后缀的全局变换。
  • 哪些页面有多个 <h1>(爬一次站,抽结构特征)。
  • 受影响 URL 的服务端渲染 HTML(不要靠 DevTools,它展示的是 hydration 后的状态)。

一步步修

按代价从小到大。

第 1 步:审一下当前状态

for url in $(cat affected-urls.txt); do
  html=$(curl -s "$url")
  title=$(echo "$html" | grep -oE '<title>[^<]+</title>' | head -1)
  h1=$(echo "$html" | grep -oE '<h1[^>]*>[^<]+</h1>' | head -1)
  echo "$url | $title | $h1"
done

输出拉进表格。一眼就能看出不一致集中在哪里。

第 2 步:合并 CMS 字段

对应该永远一致的内容类型,把 “SEO Title” 和 “Headline” 合并成一个来源字段:

// content schema
title: z.string().min(20).max(65),  // single source

// template
<title>{article.title}{brandSuffix(article.section)}</title>
<h1>{article.title}</h1>

对故意要不同的内容类型(比如清单文),保留两个字段,但在 CI 里强制相似度检查。

第 3 步:CI 里加一个相似度检查

function tokenJaccard(a: string, b: string): number {
  const toks = (s: string) => new Set(s.toLowerCase().match(/\w+/g) ?? []);
  const A = toks(a), B = toks(b);
  const inter = [...A].filter(x => B.has(x)).length;
  return inter / (A.size + B.size - inter);
}

for (const article of allArticles) {
  const score = tokenJaccard(article.title, article.h1);
  if (score < 0.5) {
    console.warn(`Low similarity: ${article.slug}: ${score.toFixed(2)}`);
  }
}

title 和 H1 实词共享率低于一半就让 build 失败(或警告)。

第 4 步:长标题去掉品牌后缀

<title> 算上品牌后缀如果超过 60 字符左右,把后缀丢掉:

const FULL = `${article.title} | ${BRAND}`;
const titleTag = FULL.length > 65 ? article.title : FULL;

或者让两边都带品牌:

<title>{article.title} | {BRAND}</title>
<h1>{article.title}</h1>  // brand omitted from H1, kept in template chrome only

哪个策略都行 —— 一致就好。

第 5 步:强制一个页面只有一个 <h1>

模板里:

{article && <h1>{article.title}</h1>}
{!article && pageType === 'category' && <h1>{categoryName}</h1>}
{/* no h1 in hero block — switch to h2 */}

修完爬一次站,断言每个页面正好一个 <h1>

第 6 步:H1 文本永远服务端渲染

不要在首次渲染之后用 JavaScript 设置 H1。要么 HTML 里就有最终 H1,要么接受 Google 可能用别的信号代替。

第 7 步:对修好的 URL 重新申请索引

挑 Top 10-20 个 URL,走 URL Inspection → Request indexing。每周跟 SERP 标题;通常修复后 2-3 次抓取以内改写就停止。

验证

  • 抽样 URL 的 title 与 H1 一致或明显在表达同一件事。
  • 没有 URL 含多个 <h1>
  • Search Console 上 Google 改写标题的数量逐周下降。
  • 之前被改写过的 URL 点击率回稳或回升。
  • curl 任一 URL,响应里直接含最终 H1 文本。

长期预防

  • 选一个编辑策略:H1 和 <title> 一致,或 <title> = H1 + 受控后缀。写下来。
  • CMS 里用单个字段做标题来源,由它派生 <title><h1>
  • CI 断言 title/H1 相似度和单 H1。
  • 避免动态 H1;非要做就服务端 ship 最终文本。
  • 每月审一次 Google 改写事件,在影响排名之前发现回退。

常见坑

  • 只在 <title> 上加 session ID 或 A/B 变体。编辑看不到,Google 看得到。
  • 把”Google 改写了我的标题”当随机事件放着。它非常确定 —— 触发条件通常都能修。
  • 用 CSS display:none 隐藏 <h1>,以为 Google 会忽略。Google 仍会解析为 H1,而且这种隐藏写法有风险。
  • 用带 role=“heading” 的 <div> 代替真正的 <h1> 元素。用真标签。
  • 五个词的 H1 配 16 个词的 <title>。长度差本身就是 Google 用来判断不可信的信号。

FAQ

Q:<title><h1> 必须一模一样吗?

可以不同,但大部分实词应该共享。常见做法:H1 = “Sourdough Bread Recipe”,<title> = “Sourdough Bread Recipe — Step-by-Step Guide | Acme”。加修饰词没问题;完全无关的 <title> 不行。

Q:可以没有 H1 吗?

技术上 HTML 合法,但 Google 把 H1 当作判断页面主题的多个信号之一。零 H1 让 Google 退回 <title> 加正文,反而更容易被改写。

Q:Google 一定会改写不一致的标题吗?

不。Google 判定 <title> “与页面不一致”时才改。跟 H1 不一致只是触发条件之一。修了不代表 Google 永远不动你的 title —— 只是降低被改写的频率。

Q:H1 是 logo 图片,对 SEO 不好吗?

不好 —— Google 需要文本。用真正带文本的 <h1>,CSS 把 logo 样式做出来;或把 logo 移到兄弟元素,H1 保持文本。

标签: #SEO #排查 #title-tag #h1 #google-rewrite