iframe 终极指南
作者:Nada Rifki✏️
iframe 元素(内联框架的缩写)可能是最古老的 HTML 标签之一,由 Microsoft Internet Explorer 于 1997 年随 HTML 4.01 引入。
尽管所有现代浏览器都支持它们,但许多开发人员写了无数的文章建议不要使用它们。
我相信,即使他们的名声不好,也不应该阻止你信赖他们。他们有很多合法的用例。
此外,保护它们的安全并不难,所以您不必担心用户的计算机受到感染。
为了帮助您形成自己的观点并提高您的开发技能,我们将介绍有关这个有争议的标签的所有基本知识。
我们将介绍 iframe 元素提供的大部分功能,并讨论如何使用它们,以及如何利用 iframe 来应对一些棘手的情况。最后,我们将讨论如何保护 iframe 以避免潜在的漏洞。
什么是 iframe,何时使用它?
开发人员主要使用 iframe 标签在当前 HTML 文档中嵌入另一个 HTML 文档。
当您必须在您的网站上添加第三方小部件(如著名的 Facebook 点赞按钮)、YouTube 视频或广告部分时,您可能已经与它有过交集。
例如,下面的代码将显示一个 500px 的正方形,其中包含 google 主页:
<iframe src="https://www.google.com/" height="500px" width="500px"></iframe>
下面是另一个示例,其中我们显示一个按钮,用于在 Twitter 上发布您的网页:
<iframe src="https://platform.twitter.com/widgets/tweet_button.html" style="border: 0; width:130px; height:20px;"></iframe>
考虑 iframe 时必须牢记的是,它允许您嵌入具有浏览上下文的独立 HTML 文档。
因此,它将与父级的 JavaScript 和 CSS 隔离。这是使用 iframe 的有效目的之一:在应用程序和 iframe 内容之间提供一定程度的隔离。
尽管如此,正如您将在本指南中看到的,这种分离并不是那么完美。
iframe 仍然可能以令人讨厌或恶意的方式运行:例如触发弹出窗口或自动播放视频。
为了说明这种与 JavaScript 和 CSS 的隔离有多么方便,让我们看一下以下两种情况:
在一个应用程序中,用户可以创建电子邮件并将其保存为模板。我需要在特定页面上列出这些模板,以便用户预览并选择一个。
但是,为了防止当前网站的 CSS 影响这些模板的样式,我发现使用带有srcdoc
属性的 iframe 是最干净的解决方案。
<iframe srcdoc="<html><body>The content you see here will never be affected by the CSS of its parent container. It supposed to be rendered in black on a white background.</body></html>"></iframe>
另一个 iframe 拯救我生命的例子是,我需要为客户构建一个所见即所得的编辑器。但这类编辑器的问题在于,你必须找到一种方法,确保当用户点击界面上的所有按钮时,焦点和选择仍然保持。
因为 iframe 提供了一个独立的环境,这意味着当您在其外部单击时,焦点或选择永远不会丢失。
通过使用 iframe 和父级之间的通信事件(本文后面将详细介绍如何操作),我成功地设计出了一个功能强大的编辑器。
你需要知道的属性
到目前为止,我们可以使用八个属性来自定义 iframe 的行为或样式。
<iframe
src="https://google.com/" <!-- Sets the address of the document to embed -->
srcdoc="<p>Some html</p>" <!-- Sets the HTML content of the page to show -->
height="100px" <!-- Sets the iframe height in pixels -->
width="100px" <!-- Sets the iframe width in pixels -->
name="my-iframe" <!-- Sets the name of the iframe (mainly used to reference the element in JavaScript -->
allow="fullscreen" <!-- Sets the feature policy for the iframe. -->
referrerpolicy="no-referrer" <!-- Set the referrer to send when fetching the iframe content -->
sandbox="allow-same-origin" <!-- Sets the restrictions of the iframe (more on this below) -->
></iframe>
您可能会发现上面列出的内容更多,但请记住,HTML5 不再支持它们:align
、、、和。frameborder
longdesc
marginheight
marginwidth
scrolling
注意:默认情况下,iframe 元素周围有边框。要删除边框,可以使用 style 属性将 border CSS 属性设置为 none。
<iframe src="https://logrocket.com/" style="border: none;"></iframe>
iframe 事件和通信
加载和错误
因为 iframe 是一个文档,所以您可以使用大多数全局事件处理程序。
当您启动 iframe 时,其中两个可以派上用场,以改善体验,例如显示旋转器或特定消息来帮助用户:
-
该
load
事件。当 iframe 完全加载时触发。换句话说,所有静态资源都已下载,并且 DOM 树中的所有元素都已触发其 load 事件。 -
error
加载失败时触发的事件。
onload
您可以分别使用和属性来收听它们onerror
:
<iframe src="https://logrocket.com/" onload="onLoad()" onerror="onError()"></iframe>
或者您可以通过编程方式将监听器添加到您的 iframe。
// For a new iframe
const iframe = document.createElement("iframe");
iframe.onload = function() {
console.log("The iframe is loaded");
};
iframe.onerror = function() {
console.log("Something wrong happened");
};
iframe.src = "https://logrocket.com/";
document.body.appendChild(iframe);
// For an existing iframe
const iframe = document.querySelector('.my-iframe');
iframe.onload = function() {
console.log("The iframe is loaded");
}
iframe.onerror = function() {
console.log("Something wrong happened");
}
与 iframe 通信
在父级和 iframe 之间发送消息非常简单。你必须使用此处 (https://github.com/iframe/iframe) 中记录的postMessage
函数。
从父级到 iframe
从父元素发送消息:
const myiframe = document.getElementById('myIframe')
myIframe.contentWindow.postMessage('message', '*');
并在 iframe 中收听:
window.onmessage = function(event){
if (event.data == 'message') {
console('Message received!');
}
};
从 iframe 到父级
从 iframe 发送消息:
window.top.postMessage('reply', '*')
然后在父级中收听:
window.onmessage = function(event){
if (event.data == 'reply') {
console('Reply received!');
}
};
注意:请记住,当您需要调试某些东西时,您可能会遇到一些棘手的情况,因为消息是“发射后不管”的(即,没有真正的错误处理)。
安全
当您使用 iframe 时,您主要处理来自第三方的、您无法控制的内容。
因此,您的应用程序存在潜在漏洞的风险就增加了,或者您不得不处理糟糕的用户体验(例如烦人的视频自动播放)。
值得庆幸的是,您可以将特定功能列入黑名单或白名单。
您必须使用我们之前讨论过的sandbox
和allow
属性。
请记住,一个好的经验法则是始终授予资源完成其工作所需的最低限度的权限。安全专家将此概念称为“最小特权原则”。
沙盒属性
以下是沙盒标志及其用途的完整列表:
旗帜 | 细节 |
---|---|
允许表格 | 允许表单提交。 |
允许模式 | 允许资源打开新的模式窗口。 |
允许方向锁定 | 允许资源锁定屏幕方向。 |
允许指针锁定 | 允许资源使用指针锁 API。 |
允许弹出窗口 | 允许资源打开新的弹出窗口或选项卡。 |
允许弹出窗口退出沙盒 | 允许资源打开不会继承沙盒的新窗口。 |
允许演示 | 允许资源开始演示会话。 |
允许同源 | 允许资源保持其来源。 |
允许脚本 | 允许资源运行脚本。 |
允许顶部导航 | 允许资源导航顶级浏览上下文。 |
允许用户激活顶部导航 | 允许资源导航顶级浏览上下文,但只能由用户手势启动。 |
您可以自行定义可以授予每个 iframe 哪些权限。
例如,如果您的 iframe 只需要提交表单并打开新的模式窗口,则可以这样配置沙盒属性:
<iframe sandbox="allow-forms allow-modals" src="https://www.something.com/"></iframe>
对于配置了沙盒属性并且资源中的某个功能无法正常工作的情况,可能是因为它缺少特定的标志。
确保您对它们有更多的了解,以便快速调试问题。
另外,请记住,使用空的沙盒属性将完全对 iframe 进行沙盒处理。
这意味着 iframe 内的 JavaScript 将不会被执行,并且上面列出的所有权限都将受到限制(例如创建新窗口或加载插件)。
空沙盒属性主要用于静态内容,但会大大降低其他资源正常工作所需的能力。
<iframe sandbox="allow-forms allow-modals" src="https://www.something.com/"></iframe>
注意:Internet Explorer 9 及更早版本不支持沙盒属性。
属性allow
此allow
属性目前处于实验阶段,仅支持基于 Chromium 的浏览器。它允许您允许白名单中的特定功能,例如允许 iframe 访问加速度计、电池信息或摄像头。
可用的标志超过 25 个,因此我不会在这里全部列出。您可以在 Mozilla 功能策略文档中浏览它们。我在下表中总结了最受欢迎的标志:
旗帜 | 细节 |
---|---|
加速度计 | 允许访问加速度计接口 |
环境光传感器 | 允许访问 AmbientLightSensor 接口 |
自动播放 | 允许自动播放视频和音频文件 |
电池 | 允许访问电池状态 API |
相机 | 允许访问相机 |
全屏 | 允许访问全屏模式 |
地理位置 | 允许访问地理位置 API |
陀螺仪 | 允许访问传感器 API 陀螺仪接口 |
磁力仪 | 允许访问传感器 API 磁力计接口 |
麦克风 | 允许访问设备麦克风 |
米迪 | 允许访问 Web MIDI API |
支付 | 允许访问付款请求 API |
USB | 允许访问 WebUSB API |
颤动 | 允许访问振动 API |
关于 iframe 你需要知道的事情
如何处理不支持 iframe 的浏览器
<iframe>
如果浏览器不支持 iframe,它将显示开始标签和结束标签之间的内容</iframe>
。
因此,您应该始终考虑放置一条警告消息,作为对那些可怜用户的后备。
<iframe>
<p>Your browser does not support iframes.</p>
</iframe>
如何才能将 iframe 渲染得像它实际上是父文档的一部分(即没有边框和滚动条)?
🤓 该seamless
属性正是为此目的而引入的。它仍处于实验阶段,并且浏览器支持不佳(只有基于 Chromium 的浏览器才能理解它)。
在撰写本文时,它也不是 W3C HTML5 规范的一部分。
<iframe seamless src="https://logrocket.com/"></iframe>
iframe 会影响我的网站的 SEO 吗?
我对此了解不多,所以不得不深入挖掘一下。关于这个问题有很多猜测。
长期以来,爬虫无法理解它们,但现在情况已不再如此。我找到的最相关的答案来自这篇文章,今天的结论似乎是:
由于搜索引擎会将 iframe 中的内容视为其他网站的内容,因此您最多只能指望它不会产生任何影响。iframe 对您的搜索引擎排名既不会有任何帮助,也不会造成任何损害。
因此,最好假设通过 iframe 显示的内容可能未被编入索引或无法显示在 Google 的搜索结果中。一种解决方法是确保为其显示的内容提供额外的文本链接,以便 Googlebot 能够抓取并编入索引。
注意:您也不必担心重复内容问题,因为当今的网络爬虫通常可以识别它们。
iframe 会影响我的网站的加载速度吗?
页面上的每个 iframe 都会增加所使用的内存以及其他计算资源(如带宽)。
因此,您不应过度使用 iframe 而不监控正在发生的事情,否则最终可能会损害您的页面性能。
为了避免 iframe 减慢页面速度,一个好的方法就是延迟加载它们(即,仅在需要时加载它们,例如当用户滚动到它们附近时)。
loading="lazy"
只需向标签添加属性即可轻松实现这一点。
请记住,在撰写本文时,所有基于 Chromium 的现代浏览器都支持此功能。您可能会对lazyload 库感兴趣,因为它可以在任何地方使用。
<iframe src="https://logrocket.com/" loading="lazy"></iframe>
注意:如果您还不知道的话,该loading="lazy"
属性也适用于标签。😜img
如何让 iframe 具有响应能力?
随着越来越多的人使用手机浏览网页,确保每个界面都具有响应能力至关重要。
但是当您的页面中有 iframe 时您该怎么做呢?
我们可以专门写一整篇指南来介绍如何让 iframe 响应式布局。但我只想分享两篇很棒的文章:
-
第一篇文章(可能是最简单的解决方案)将向您展示如何通过将 iframe 包装在另一个 HTML 元素中并向其中添加一些 CSS 属性来实现这一点。
-
第二篇文章将向您展示如何通过处理纵横比使 iframe 具有响应性。
-
还有Iframe Resizer Library,但请记住,它附带了很多您可能实际上并不需要的附加功能。
注意:如果您在项目中使用引导库,则您可以直接使用embed-responsive
和embed-responsive-16by9
来使您的 iframe 具有响应能力。
<div class="embed-responsive embed-responsive-16by9">
<iframe src="https://logrocket.com/" loading="lazy"></iframe>
</div>
如何防止iframe加载时出现白色闪烁
是的,朋友们,这个问题有解决办法。在这篇文章中,Chris Coyier分享了一小段代码,它用一些 CSS 代码隐藏了页面上的所有 iframe,并在窗口加载完成后将其移除,然后显示出来。
如何重新加载 iframe 的内容
非常简单!由于你可以使用 访问 iframe 的 window 元素contentWindow
,因此你需要执行以下操作:
// Get the iframe
const iframe = document.getElementById('myIframe');
// Reload the iframe
iframe.contentWindow.location.reload();
我希望本指南能够帮助您提高对 iframe 的了解。
虽然它们在加载不受信任的内容时可能不安全,但它们也提供了一些显著的优势。因此,您不应该完全禁止它们在您的开发工具库中运行,而应该仅在相关情况下使用它们。
如果你对本文有任何补充,可以通过下面的评论联系我,或者在 Twitter 上关注我@RifkiNada
插件:LogRocket,一个用于 Web 应用的 DVR
LogRocket是一款前端日志工具,可让您重播问题,就像它们发生在您自己的浏览器中一样。您无需猜测错误发生的原因,也无需要求用户提供屏幕截图和日志转储,LogRocket 允许您重播会话以快速了解问题所在。它可与任何应用程序完美兼容,无论使用哪种框架,并且提供插件来记录来自 Redux、Vuex 和 @ngrx/store 的更多上下文。
除了记录 Redux 操作和状态之外,LogRocket 还记录控制台日志、JavaScript 错误、堆栈跟踪、带有标头 + 正文的网络请求/响应、浏览器元数据以及自定义日志。它还会对 DOM 进行插桩,以记录页面上的 HTML 和 CSS,即使是最复杂的单页应用程序,也能重现像素完美的视频。
免费试用。
文章《iframe 终极指南》最先出现在LogRocket 博客上。
鏂囩珷鏉ユ簮锛�https://dev.to/bnevilleoneill/the-ultimate-guide-to-iframes-3c84