target="_blank"必须搭配rel="noopener noreferrer"才安全,否则新页面可通过window.opener劫持原页并泄露Referer;浏览器仅支持_self、_blank、_parent、_top和framename五种合法target值。

单独写 target="_blank" 是不安全的,必须搭配 rel="noopener noreferrer" 才能防止新页面劫持原页;浏览器只认五种合法值,其他写法看似有效实则 fallback 到 _self。
为什么 target="_blank" 必须加 rel="noopener noreferrer"
不加 rel="noopener" 时,新打开的页面能通过 window.opener 直接修改原页面地址、读取 DOM,甚至执行重定向。这不是假设——攻击者只要在目标页写一行 window.opener.location = "https://fake-login.example",用户当前页就跳转了。
只加 rel="noopener" 却漏掉 noreferrer,Referer 头仍会泄露来源 URL,影响隐私和部分 API 鉴权逻辑。
常见错误包括:
立即学习“前端免费学习笔记(深入)”;
-
target="blank"(漏下划线)→ 浏览器当普通字符串处理,等同于target="_self",当前页跳转 -
target="_new"或target="new"→ 非标准值,所有现代浏览器都忽略,退化为_self
target 的合法值到底有哪些
W3C 和 HTML Living Standard 明确只承认以下五类值:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
-
_self:默认行为,当前标签页加载(可省略) -
_blank:唯一推荐用于“新开页”的值 -
_parent:仅在嵌套<iframe>场景中有效,指向父级上下文 -
_top:跳出所有<iframe>层级,在顶层窗口加载 -
framename:匹配页面中某个<iframe name="xxx">,现已极少使用
像 _window、_newtab、new 这类写法,浏览器不会报错,但也不会生效——它们只是被当作自定义窗口名,而由于对应窗口不存在,最终仍 fallback 到 _self。
Vue/React 里用 <a> 容易踩的坑
框架不改变 HTML 语义,但容易因绑定方式绕过原生行为:
- 用
@click.prevent="window.open(url)"替代原生<a href="..." target="_blank">→ 右键菜单丢失“复制链接地址”,SEO 不识别,且 SSR 环境直接报ReferenceError: window is not defined - 动态生成
href时未校验,导致href="undefined"或href="javascript:void(0)"→ 点击无响应或触发意外 JS 行为 - 在
<router-link>或<Link>中硬塞target→ 这些组件不支持该属性,会被忽略,必须退回到原生<a>
外部链接才该用 target="_blank"
屏幕阅读器会播报 target="_blank",但不会自动说明“将在新标签页打开”。用户可能误以为当前页会跳转,结果发现原页面还在、新页又没注意——尤其对低视力或认知障碍用户更不友好。
所以实际项目中建议:
- 只对外部链接(如跳转到第三方网站)启用
target="_blank" - 内部路由跳转一律用
_self,避免打断单页应用的导航流 - 如果必须开新页,务必同时带上
rel="noopener noreferrer",不能只写一个
最容易被忽略的是:哪怕你写了 target="_blank",只要没配 rel,这个链接就是带后门的。


















