hreflang 仅向搜索引擎声明语言和地区版本关系,不触发跳转或影响渲染;必须严格遵循 BCP 47 规范、双向互指、绝对 URL、静态输出,并与 lang 属性各司其职。

hreflang 不会自动跳转、不控制渲染、不替代 lang 属性——它只是一组给搜索引擎看的声明,写错一个字符或漏一条反向链接,整组就失效。
hreflang 值必须严格匹配 BCP 47 规范
Google 和 Bing 的爬虫解析器不宽容。填 zh_CN、EN-us、chinese 或 zh-Hant-TW(多一个连字符)都会被整条忽略。
-
zh-Hans和zh-CN是两个不同值,混用会导致语言闭环断裂 - 通用英语优先用
en;有地区差异时必须用en-US、en-GB等,不能只写en-us(小写语言是硬性要求) -
x-default只能出现一次,且必须指向兜底页(如国际首页),不能和某个具体语言重复 - 繁体中文推荐按地区细分:
zh-Hant-HK、zh-Hant-TW,避免笼统用zh-Hant
每页必须双向互指 + 自指 + 绝对 URL
不是“英文页写中文链接就够了”,而是每个语言页的 <head> 都要完整包含全部语言版本的 <link rel="alternate" hreflang="...">,含自己。
- 英文页
https://example.com/en/要声明:hreflang="en"指向自身,hreflang="zh-Hans"指向中文页,hreflang="x-default"指向兜底页 - 中文页
https://example.com/zh/必须反向声明:hreflang="zh-Hans"指向自身,hreflang="en"指向英文页——漏掉这条,Google 就认为“中文版没有对应英文版” -
href必须是绝对 URL:https://example.com/zh/合法,/zh/或./zh/直接被忽略 - 所有语言页的协议、域名、路径结构必须一致(不能有的用
https,有的用http;不能有的走子目录,有的走子域名)
JS 动态注入 hreflang 标签等于没写
搜索引擎爬虫基本不执行 JS,所以靠 document.head.appendChild() 或 innerHTML += 加的 <link rel="alternate"> 对 SEO 零作用,还容易引发重复声明冲突。
- 后端静态输出或构建时生成是唯一可靠方式(如 Hugo 模板循环、Eleventy 数据驱动)
- 如果必须 JS 注入(例如 SPA 多语言路由),务必先清理旧标签:
document.querySelectorAll('link[rel="alternate"][hreflang]')→ 显式.remove() - 禁止用
innerHTML +=拼接,易覆盖已有标签;改用replaceChildren()更可控 - 验证是否生效,不能靠浏览器开发者工具看 DOM,得用 Google Search Console「国际化报告」或 Screaming Frog 抓取比对
hreflang 和 lang 属性完全无关
这是最常被混淆的一点:hreflang 影响索引与流量分发,lang 决定浏览器如何渲染、朗读、拼写检查——两者职责分离,必须各自配齐。
- 页面
<html lang="zh-Hans">才会让屏幕阅读器用中文发音,hreflang="zh-Hans"完全不影响这个行为 - 嵌入的多语言段落需单独加
<p lang="en">,否则辅助技术仍按根lang解析 - 用户语言跳转逻辑(如根据
navigator.language重定向)必须由服务端(Nginx / Node.js)或前端 JS 单独实现,与hreflang无关 -
canonical应始终指向当前页自身 URL,误设为指向主站首页会导致其他语言页被判定为重复内容
真正难的不是写几行 <link>,而是确保每个语言页的声明闭环、格式零误差、输出时机正确——任何一环出问题,搜索引擎看到的就不是一组语言关系,而是一堆互相矛盾的信号。


















