target="_blank"有时不生效,主要因缺失rel="noopener noreferrer"导致浏览器(如chrome 88+)静默降级为同窗口跳转,或受跨域策略、iframe/sandbox环境限制;同时其实际行为还受用户设置、按键操作及脚本触发方式影响。

为什么 target="_blank" 有时不生效?
常见原因是页面启用了 rel="noopener" 或 rel="noreferrer",但没配对写全,或者浏览器策略拦截了未声明 rel 的跨域链接。Chrome 88+ 对缺失 rel="noopener" 的 target="_blank" 会静默降级为同窗口跳转(尤其在 iframe 或 sandbox 环境下)。
必须同时指定:
– target="_blank"(触发新窗口)
– rel="noopener noreferrer"(安全兜底,防 window.opener 泄露)
示例:
<a href="https://example.com" target="_blank" rel="noopener noreferrer">打开外部链接</a>
target="_blank" 在不同场景下的行为差异
它不等于“总开新标签页”:实际表现取决于用户浏览器设置、是否按住 Ctrl/Command 键、以及当前 tab 是否由脚本触发(如 window.open())。移动端 Safari 默认在新标签页中打开,但部分 Android 浏览器可能复用当前 tab。
- 用户点击时:由浏览器决定新开 tab 还是新开 window(通常可配置)
- JavaScript 模拟点击(如
link.click()):多数现代浏览器会拦截,除非在用户手势事件(如click回调)中触发 - 同一域名内链接:仍受
rel影响,但无跨域安全风险,rel="noopener"可省略noreferrer(但建议保留)
不加 rel="noopener" 有什么实际风险?
攻击者可在新页面通过 window.opener.location 重定向原页面,或读取原页面 DOM(如果同源),造成钓鱼或 XSS 链式利用。即使目标站是第三方,只要没加 rel="noopener",恶意站点就能拿到你的页面引用。
更隐蔽的问题:
– 若目标页执行 window.opener.location = "https://phishing.site",你的页面会被无声劫持
– Vue/React 中动态生成的 <a></a> 标签容易漏掉 rel,尤其用 v-bind:href 或 href={url} 时
务必检查所有带 target="_blank" 的链接,包括 CMS 输出、Markdown 渲染结果、富文本编辑器插入内容。
如何批量修复已有 a 标签?
不能只靠正则全局替换,因为要判断是否已存在 rel 属性并合并值。推荐用 DOM 操作一次性补全:
document.querySelectorAll('a[target="_blank"]')
.forEach(a => {
if (!a.rel.includes('noopener')) {
a.rel = (a.rel + ' noopener').trim();
}
if (!a.rel.includes('noreferrer')) {
a.rel = (a.rel + ' noreferrer').trim();
}
});
注意:
– 这段脚本需在 DOM 加载完成后执行(如 DOMContentLoaded)
– 如果页面用前端框架渲染,应在组件挂载后运行,或改用指令/插件方式注入
– SSR 页面需在服务端模板中直接写死 rel,避免依赖客户端 JS 修复
真正麻烦的不是写法,而是历史遗留代码里那些没加 rel 的链接——它们往往藏在 CMS 插件、第三方 widget、甚至静态 HTML 片段里,人工 audit 成本远高于加一行属性。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











