target="_blank"需配rel="noopener"防反向Tabnabbing攻击,href不能为空,移动端WebView可能不支持,应优先用rel="noopener noreferrer"并统一注入。

target="_blank" 点开没反应?先检查 href 和 rel
不是所有 target="_blank 都能生效。最常见的情况是:没写 href,或者 href 是空字符串、#、javascript:void(0) —— 浏览器会直接忽略 target 属性。另外,移动端某些 WebView(尤其旧版)根本不支持 target,必须用 window.open() 替代。
安全上更关键的是:target="_blank" 单独使用默认不安全。新页面能通过 window.opener 控制原页面跳转或读取历史记录,这是真实被用于钓鱼的“反向 Tabnabbing”攻击。必须配 rel="noopener" 才能切断这个引用。只加 rel="noreferrer" 不行——它不解决 opener 泄露问题,旧版 Safari 甚至仍允许访问 window.opener。
-
rel="noopener"是强制项,现代浏览器(Chrome 49+、Firefox 52+、Safari 10.1+)都支持 - 需要兼容极老 Safari?补上
noreferrer:用rel="noopener noreferrer" - Vue/React 动态渲染链接时容易漏掉
rel,建议封装成组件统一注入
target="_self" 显式写出来,多数时候是冗余
target="_self" 就是默认行为,除非你之前用过 <base target="_blank"> 或在父级 <iframe></iframe> 里设了 name,否则它和不写 target 完全等价。它不会“强制刷新当前页”,也不会“避免历史记录”——想控制后退行为,得用 history.replaceState()。
常见误用场景:
立即学习“前端免费学习笔记(深入)”;
- 在 iframe 里点击链接却跳出 iframe?不是因为缺
_self,而是<iframe></iframe>没设name,导致target="xxx"匹配失败,最终降级为_blank或_self,行为不一致 - CMS 或编辑器自动生成
target="_self",纯属模板冗余,可安全删掉
window.open() 的 opener 陷阱比 target 更隐蔽
window.open("url", "_blank") 看似和 target="_blank" 等价,但实际更危险:它默认保留 window.opener 引用,且不自动加 noopener。如果没手动处理,新窗口照样能劫持原页面。
正确做法是显式传入安全参数:
- 必须用户主动触发(如 click 内调用),否则会被弹窗拦截
- 第二个参数写
"_blank"只是告诉浏览器“新开匿名窗口”,不是强制新标签页 - 第三个参数要包含
"noopener":例如window.open(url, "_blank", "noopener") - 返回值可能为
null(被拦截时),记得判断
自定义 target 名字(如 "myFrame")容易拼错且行为不一致
这种写法依赖严格匹配 <iframe name="myFrame"></iframe>,大小写敏感、不能有空格或特殊字符。一个末尾空格、大小写不一致,就会匹配失败——不同浏览器降级策略不同:有的当 _blank,有的当 _self,调试起来非常难定位。
真正需要复用窗口的场景极少,而且跨域时 Chrome 92+ 已限制重用逻辑。与其冒险拼名字,不如优先用 target="_blank" + rel="noopener noreferrer" 这种语义明确、兼容性好、无需 JS 支持的方案。
复杂点在于:服务端或 CMS 输出的富文本里,target="_blank" 往往漏掉 rel。这时候不能靠人肉补,得在渲染层统一拦截并注入——但要注意合并已有 rel 值(比如 rel="nofollow" 应变成 rel="nofollow noopener noreferrer")。



















