SEO 搜索引擎优化之 a 标签 rel 属性
太阳作者太阳
原创内容采用 CC-4.0 协议发布,转载请注明出处

对于属性 rel 可以参考 MDN文档 上面描述了这个属性在各种标签下可选的值。对于<a>rel 属性标签主要关注这四个值:

  • nofollow 表示当前文档的原作者或出版商不认可被引用的文件。
  • external 它表示引用的文档不是当前网站的一部分。这可以与属性选择器一起使用,使外部链接的样式向用户表明他们将离开当前网站。
  • noopener 元素的属性noopener关键字指示浏览器导航到目标资源,而不授予新的浏览上下文对打开它的文档的访问权限 - 通过不在打开的窗口上设置属性。
  • noreferrer包括这个值使得 referrer 未知(不会包含 Referer 标头),并创建一个顶级的浏览上下文,就像 noopener 也被设置一样。

浏览器安全相关

noopener用于浏览器安全防护,防止钓鱼攻击。 当链接使用 target="_blank" 打开新页面时,新页面可以使用以下语句控制父页面:

if (window.opener) {  
    window.opener.location="https://nenufm.com?referrer="+document.referrer;  
}

链接加上rel="noopener"后,则新页面被限制访问window.opener。

noreferrernoopener类似,设置了rel="noreferrer"后,链接的新页面被限制访问window.opener。同时,新页面无法获取document.referrer信息,该信息包含了来源页面的地址。因为一些旧的浏览器不支持noopener,所以为也兼容,会同时设置两个属性值rel="noopener noreferrer"

SEO 优化相关

nofollow 用于告知搜索引擎,当前链接不需要追踪,或者我不想表达对这个链接目标的认可。它更像是一个给搜索引擎的链接关系提示,而不是浏览器安全能力。以前我会把它理解成“绝对不追踪、不传递权重”,现在看这个说法过于绝对。以 Google 的文档表述为准,nofollowugcsponsored 这些值是帮助搜索引擎理解出站链接性质的标记,搜索引擎会按自己的规则处理。

  • 反垃圾链接 网站通常有留言功能,一些人会利用这个功能,在评论的时候,留下自己站点的链接。加上nofollow进行屏蔽后,可以防止当前站点的权重流失。
  • 节约蜘蛛资源 每个站点,搜索引擎每天派出的爬虫数是一定的。尽量把爬虫引导到有用的链接上,有利于重要页面的收录。不过不要把 nofollow 当作站点结构优化的主工具,站内重要页面仍然应该靠清晰导航、列表页、分类页和站点地图组织。

external 用来说明链接目标不是当前站点的一部分。它本身不会让链接在新窗口打开,真正控制新窗口的是 target="_blank"。所以如果只是希望外部链接新开窗口,仍然要写 target="_blank";如果要表达“这是外部链接”,再配合 rel="external"

Google 搜索文档参考

对于希望 Google 无任何限定条件便直接提取和解析的常规链接,无需添加 rel 属性。

rel="sponsored" 标记广告链接或付费展示位置链接(通常称为“付费链接”)以前推荐使用 nofollow 属性仍可以使用该属性进行标记,但更建议使用 sponsored 标记。

rel="ugc" 标记用户生成的内容(例如评论和论坛帖子)的链接。

rel="nofollow" 如果其他值不适用,并且希望 Google 不跟踪您网站上的出站链接,或不从您的网站上抓取链接页,使用 nofollow

总结

日常在使用中对于文章中所引用的链接,添加 rel="noopener" 就足够了。在 wordpress 中会对所有文章中的网站外部链接都添加 rel="noopener",这并不会影响网站的 SEO。对于页面上那种必须展示、但不需要表达认可的外部链接,例如备案地址,可以添加 rel="noopener nofollow",把它作为一个“不希望搜索引擎跟随这个出站链接”的提示。

更新:从这次博客迁移得到的经验

2026 年重新整理博客时,我对这几个概念有了更清晰的边界:rel 只描述“当前页面和链接目标之间的关系”,它不是站点级爬虫控制工具,也不是页面索引控制工具。要不要抓取一个路径,主要看 robots.txt;要不要把一个页面放进搜索结果,主要看页面上的 noindex 或响应头;要告诉搜索引擎站点有哪些公开页面,主要靠 sitemap.xml

这次我把博客的 robots.txt 调整成了三层:

User-Agent: Googlebot
User-Agent: Bingbot
Allow: /

User-Agent: GPTBot
User-Agent: ClaudeBot
Allow: /
Allow: /blog/page/
Allow: /blog/category/
Allow: /blog/categories
Allow: /blog/tag/
Disallow: /blog/

User-Agent: *
Allow: /

这里的思路不是“全站屏蔽 AI”,而是只禁止 AI 抓取文章正文路径,仍然允许访问首页、分类、标签、分页这些站点界面。搜索引擎仍然允许正常抓取。原因是我希望普通搜索引擎能索引公开文章,但不希望 AI 训练类爬虫直接批量抓正文。需要注意的是,robots.txt 只对遵守协议的爬虫有效,它不是访问控制,也不是版权保护。

同时我也重新看了 sitemap.xml。以前我很容易把所有博客文章都写成:

<changefreq>weekly</changefreq>
<priority>0.7</priority>

现在觉得这种写法不太符合个人博客实际。这个站点的文章多数是历史内容,不会每周更新;真正更重要的是首页、博客列表、分类入口和准确的 lastmod。Google 文档也明确提到,Google 会忽略 prioritychangefreq,更看重准确可信的 lastmod。所以站点地图里更适合这样表达层级:

  • 首页权重最高。
  • /blog 是完整内容索引,权重仅次于首页。
  • 分类入口和分类页属于中高权重。
  • 分页归档只是浏览辅助,权重不应该高于分类页和单篇文章。
  • 单篇文章按更新时间分层,最近更新的文章可以略高,老文章不要假装每周更新。
  • 隐私政策这种必要但不适合作为搜索入口的页面,可以放低权重,甚至配合 noindex,但不要用 rel 来表达页面不索引。

最后回到 a 标签本身,我现在会这样用:

  • 普通正文引用外部资料:target="_blank" rel="noopener"
  • 不想暴露来源页面给对方统计:rel="noreferrer",但要知道它会影响对方看到的来源信息。
  • 付费、广告、赞助链接:优先 rel="sponsored",必要时可组合 nofollow
  • 用户生成内容里的链接:rel="ugc"
  • 不想表达认可、不希望搜索引擎跟随的出站链接:rel="nofollow"
  • 站内重要页面:不要随便加 nofollow,更应该通过导航、分类、标签和 sitemap 让搜索引擎自然理解结构。

也就是说,rel 解决的是链接关系;robots.txt 解决的是抓取边界;noindex 解决的是索引边界;sitemap.xml 解决的是公开 URL 发现和更新时间提示。把这四个工具混在一起,往往会得到看似“优化”但实际相互打架的配置。

更新:这次 Next.js 博客 SEO 实际补了什么

这次给当前博客做 SEO 检查时,我发现基础设施已经有了:robots.txtsitemap.xmlfeed.xml 都能生成,公开内容也已经按 access: public 过滤。真正缺的是页面级信息不够完整。文章页只有 titledescription,列表页、分类页、标签页也基本依赖全局标题。搜索引擎能抓到页面,但很难从页面头部直接理解“这是哪一篇文章、规范地址是什么、社交分享图是什么、这页是否应该索引”。

这次实际补的不是“玄学关键词”,而是几类可以验证的元数据。

第一类是规范 URL。每个关键页面都补了 canonical:首页是 /,文章页是 /blog/:slug,分类页是 /blog/category/:area,标签页是 /blog/tag/:tag。这样即使以后有旧路径、分页路径或外部参数,搜索引擎也能看到我希望它归并到哪个主地址。旧的 /content/*/page/:page 兼容路由也改成了永久重定向,意思是:这些旧地址已经迁移完成,不是临时跳转。

第二类是分享和摘要信息。文章页现在会根据文章 frontmatter 生成 Open Graph 和 Twitter card:标题用文章标题,描述优先用 description,图片优先用 thumbnail,没有合适图片时退回站点默认头像。这个东西对搜索排序本身不一定有直接帮助,但对微信、聊天工具、社交平台、收藏工具和各种阅读器的展示很重要。它解决的是“别人看到这条链接时像不像一篇完整文章”的问题。

第三类是结构化数据。文章页补了 BlogPosting JSON-LD,大致包含:

{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "文章标题",
  "description": "文章描述",
  "datePublished": "发布时间",
  "dateModified": "更新时间",
  "author": {
    "@type": "Person",
    "name": "作者"
  }
}

这不是给用户看的内容,而是给搜索引擎、阅读工具和其它机器读者看的结构化说明。它比单纯从 HTML 正文里猜测文章标题、发布时间、作者更明确。

第四类是索引策略。不是所有页面都适合进入搜索结果。文章页、首页、博客列表、分类页适合索引;分页页和标签页更像浏览辅助,容易制造大量相似页面,所以这次设置为 noindex, follow:不希望它们作为搜索结果入口,但仍然允许搜索引擎顺着页面里的链接发现文章。隐私政策也是同样思路:允许访问,但不需要作为搜索入口。

第五类是内容元数据。代码层的 SEO 补完后,如果文章本身缺 description,搜索摘要仍然会很弱。这次顺手把公开文章里缺失的 descriptionsummary 补齐了;但没有为没有合适图片的文章硬编 thumbnail。没有图时使用默认图兜底,比随便塞一张不相关图片更稳。

所以现在我对个人博客 SEO 的理解更接近一张分工表:

  • rel:描述单个链接和目标页面的关系。
  • robots.txt:告诉爬虫哪些路径可以抓,哪些路径不希望抓。
  • noindex:告诉搜索引擎当前页面不应该进入搜索结果。
  • sitemap.xml:列出公开 URL 和可信更新时间,帮助发现页面。
  • canonical:告诉搜索引擎当前页面应该归并到哪个规范 URL。
  • Open Graph / Twitter card:让链接在社交、聊天和阅读工具里展示得更完整。
  • JSON-LD:用结构化数据告诉机器这是一篇博客文章,以及标题、作者、时间、图片是什么。
  • description / summary:给搜索摘要、站内搜索、RSS 和分享卡片一个稳定的文字来源。

这些东西各自解决的问题不同。小博客不需要把 SEO 做复杂,但至少要避免三个坑:不要把 rel 当成页面索引控制;不要把 robots.txt 当成内容保护;不要只有 sitemap,却没有文章级 canonical、description 和结构化信息。