【HTML】深入全掌握 iframe:了解 its 技术原理、优缺点、最佳应用场景及实战指南
【HTML】深入全掌握 iframe:了解 its 技术原理、优缺点、最佳应用场景及实战指南
前言:
Web 应用开发中,包含其他网页的框架是很常见的需求。HTML 标签 iframe
提供了一个容器,可以用来嵌入其他页面,并且它自带了一些有用的特性,如调整大小、滚动等。
本文将深入介绍 iframe
技术原理、优缺点、最佳应用场景及实战指南,希望能帮助您更好地运用 iframe,提升 Web 应用开发效率。
一、简单介绍及原理:
<iframe>
(内嵌框架)元素是一种HTML常用元素,用于在一个HTML文档中嵌入另一个HTML文档。其实际效果是将一个文档嵌入到另一个文档中,用户在浏览器中正常浏览父文档的同时,可以看到和与子文档交互。
<iframe>
所加载的文档称为内嵌框架内容(IFC),这个文档的源可以是来自于同个域的服务器,也可以是来自于另一个域的内容。在后一种情况(即跨域访问)下,由于浏览器的同源策略,可以使用postMessage()
等方法来完成父子窗口间的通信。
其原理是使用一个内联框架,将其embedded
到宿主文档中,内联框架的大小、URL等选项由父页面决定,内联框架中的内容独立于父页面进行加载、解析和渲染。
1、iframe的主要特点:
-
实现网页的嵌套和嵌入:iframe可以在一个网页中嵌入另一个网页,从而实现多个网页的协同同时显示。
-
实现页面的局部刷新:由于iframe中的内容可以被独立加载和渲染,因此可以用于实现动态的局部更新,而不是整个页面的刷新。
-
实现网页的分块:通过iframe可以将网页按照不同的模块进行拆分、划分,从而使得网页功能更为清晰、易于维护。
-
实现不同来源的内容的展示:由于iframe可以在同一个页面中嵌入来自不同来源的内容,因此可以用于展示第三方的平台或者应用的内容,例如展示第三方的视频、新闻、广告等。
2、iframe的优点:
-
分离页面逻辑
,实现模块化,便于页面搭建; - 可以将
不同域名
的脚本隔离,增加网站的安全性; - 实现
局部刷新
,减小带宽,提升网站性能; -
解决加载缓慢
地第三方内容如图标和广告等的加载问题; - 能并行加载脚本;
-
方便管理
,如果有多个页面需要使用到iframe的内容,那么只需要修改iframe的内容就可以实现统一管理; - iframe可以
原封不动
的把嵌入的网页显示出来。
3、iframe的缺点:
- 不利于搜索引擎优化,也就是不利于
SEO
,搜索引擎难以抓取iframe
中的内容; -
iframe
加载的内容无法追踪,难以提供详细的日志记录; - 容易出现父子页面之间的传递数据等安全问题,存在
点击劫持
的攻击风险; -
iframe
会增加页面的请求次数和大小,降低页面速度。 - 会产生很多的页面,不容易管理
- 会增加服务器的
http
请求,对大型网址不可取 - 会阻塞父页面的
load
事件 - iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的
并行加载
,也就是说子文档和父文档的请求数会被计算到一起
4、解决方案:
避免以上缺点,需要采取以下措施:
- 要减少使用,避免嵌入过多内容,影响网页加载速度;
- 设置iframe的宽度和高度,避免出现页面布局混乱的情况;
- 根据需要动态配置iframe的
src
属性,避免出现安全问题; - 配合
CSS
和JavaScript
来实现iframe的样式和事件处理等需求。
5、iframe的应用场景:
- 加载网络地图等第三方应用内容;
- 可以通过iframe加载同源或者跨源的页面,实现网站的模块化。
- 嵌入来自另外域名的内容,通常可以用于社交媒体嵌入、在线视频播放等。
- 可以用于加载 JavaScript 应用程序、开启沙箱模式、提高页面的可维护性。
- 嵌入互动组件,如 Facebook 社交媒体插件、自定义地图、在线表单、即时聊天功能等等。
需要注意的是,由于iframe可以在同一个页面中嵌入来自
不同源
的内容,存在一定的安全风险。因此在使用iframe时需要注意一些安全问题
,例如页面的XSS攻击
、点击劫持
等安全问题。同时,在实现复杂的页面嵌入和嵌套时,还需要注意页面的性能
和加载速度
等问题。
二、iframe的使用
1、常用属性:
以下是<iframe>
元素的一些常用属性:
-
src
: 指定嵌套的页面URL地址; -
width
和height
: 指定iframe框架的宽度和高度; -
name
: 指定iframe的名称,在js中通过window.frames[name]
来访问该iframe; -
scrolling
: 决定是否显示滚动条,可以使用scrolling = "auto"
自动决定是否显示滚动条,或者设为"yes"和"no",指定是否一直显示或隐藏滚动条; -
frameborder
: 指定显示组件的边框,可以使用值"0"、“1"和"no”、"yes"来指定是否显示边框; -
sandbox
: 指定当网页被嵌入到iframe时可以使用哪些功能,指定内嵌框架所包含的资源的权限和安全性等; -
allowfullscreen
: 指定是否允许在全屏模式下播放视频; -
referrerpolicy
: 指定何时在HTTP请求的声明中设置referer
标头。 -
allowpaymentrequest
:允许内嵌框架中的页面向用户请求权限; -
allowpopup
:允许点击内嵌框架中的链接时弹出新窗口; -
allowtransparency
:允许内嵌框架指定透明度。
这些属性中,src
和width/height
等基础属性是必须指定的。其他属性则取决于具体的应用场景。
2、使用(操作方法):
iframe(内联框架)是一种用于在一个HTML文档中嵌入另一个HTML文档的HTML元素。以下是介绍iframe的常见使用场景和相关操作方法:
1. iframe的简单使用
在HTML页面中,可以使用<iframe>
元素来创建一个嵌套页面。使用<iframe>
元素时,需要设置src
属性来指定内嵌页面的URL。例如:
<iframe src="https://www.example.com"></iframe>
这个代码会在当前页面中嵌入来自https://www.example.com的页面内容。
2. 获取iframe元素
要获取iframe元素,可以使用JavaScript中的document.getElementById()
方法,传入iframe的id
属性值作为参数。例如:
<iframe id="myFrame" src="https://www.example.com"></iframe>
var iframe = document.getElementById('myFrame');
这个代码会获取一个指定id为“myFrame”的iframe元素。
3. 获取iframe元素值
要获取iframe元素中内容的值,可以使用JavaScript中的contentDocument
属性。例如:
<iframe id="myFrame" src="https://www.example.com"></iframe>
var iframe = document.getElementById('myFrame');
var iframeContent = iframe.contentDocument.body.innerHTML;
上述代码会获取一个指定id为“myFrame”的iframe元素的内部HTML内容。
4. iframe获取父页面的信息
在iframe中,可以使用window.parent
属性来获取其所在的父窗口对象。通过这个对象,可以实现父子页面之间的相互通信。例如:
在父页面中:
<iframe id="myFrame" src="https://www.example.com"></iframe>
function getTextFromIframe() {
var iframe = document.getElementById('myFrame');
var iframeContent = iframe.contentDocument.body.innerHTML;
iframe.contentWindow.postMessage({ message: 'getIframeContent' }, '*');
}
window.addEventListener('message', function(event) {
if (event.data.message === 'getIframeContent') {
var iframeContent = document.getElementById('myFrame').contentDocument.body.innerHTML;
event.source.postMessage({ message: 'iframeContent', content: iframeContent }, '*');
}
});
在iframe中:
window.addEventListener('message', function(event) {
if (event.data.message === 'getIframeContent') {
var iframeContent = document.getElementById('myFrame').contentDocument.body.innerHTML
event.source.postMessage({ message: 'iframeContent', content: iframeContent }, '*')
}
})
上述代码会获取一个指定id为“myFrame
”的iframe元素的内部HTML内容,并通过window.postMessage()
方法将内容发送给父窗口。在父窗口中,通过添加事件监听器,可以获取iframe传回的内容。
三、iframe的长轮询
长轮询 就是在
ajax
的readyState = 4
的时候,再次执行原函数
这里使用iframe也是一样的,异步创建iframe,然后 reload
var iframeCon = docuemnt.querySelector('#container'),
text; //传递的信息
var iframe = document.createElement('iframe'),
iframe.id = "frame",
iframe.style = "display:none;",
iframe.name = "polling",
iframe.src = "target.html";
iframeCon.appendChild(iframe);
iframe.onload = function () {
var iloc = iframe.contentWindow.location,
idoc = iframe.contentDocument;
setTimeout(function () {
text = idoc.getElementsByTagName('body')[0].textContent;
console.log(text);
iloc.reload(); // 刷新页面,再次获取信息,并且会触发 onload 函数
}, 2000);
}
这里使用 iframe 也是一样,异步创建 iframe,然后 reload。这样就可以实现 ajax 长轮询的效果。
当然,这里只是使用 reload
进行获取,也可以添加 iframe
和删除 iframe
的方式,进行发送信息,这些都是根据具体场景应用的。
另外在 iframe 中还可以实现异步加载 js 文件
,不过,iframe 和主页是共享连接池的,现在基本上都被 XHR
和 hard callback
取缔了。
四、自适应 iframe - 广告嵌入
广告通常与原文无关,如果直接在某个 div
下嵌套,会造成 网页布局的紊乱
,而且还需要引入额外的 css 和 js 文件,极大降低了网页的安全性。这些所有的弊端,都可以使用 iframe 进行解决。
可以将 iframe 理解为一个 沙盒
,里面的内容能够被 top window
完全控制,而且,主页的 css 样式不会入侵 iframe 里面的样式
默认情况下,iframe 会自带滚动条,不会全屏,如果想自适应 iframe 的话:
1、去掉滚动条
<iframe src="./iframe1.html" id="iframe1" scrolling="no"></iframe>
2、设置 iframe 的高为 body 的高
var iwindow = iframe.contentWindow;
var idoc = iwindow.document;
iframe.height = idoc.body.offsetHeight;
五、iframe 的安全性
1、防嵌套网页
iframe 享有 click
优先权,当有人在伪造的主页中进行点击的话,如果点在 iframe 上,则会默认是在操作 iframe 的页面。所以,钓鱼网站就是使用这个技术,通过诱导用户进行点击。
为了防止网站被钓鱼,可以使用 window.top
来防止网页被 iframe,即限定你的网页不能被嵌套在任何网页内:
// iframe2.html
if (window != window.top) {
window.top.location.href = correctURL;
}
2、 X-Frame-Options
X-Frame-Options
是一个相应头,主要是描述服务器的网页资源的 iframe 权限,有3个选项:
-
DENY
:当前页面不能被嵌套 iframe 里,即便是在相同域名的页面中嵌套也不允许,也不允许网页中有嵌套 iframe -
SAMEORIGIN
:iframe 页面的地址只能为同源域名下的页面 -
ALLOW-FROM
:可以在指定的 origin url 的 iframe 中加载
简单示例:
X-Frame-Options: DENY
拒绝任何iframe的嵌套请求
X-Frame-Options: SAMEORIGIN
只允许同源请求,例如网页为 foo.com/123.php,則 foo.com 底下的所有网页可以嵌入此网页,但是 foo.com 以外的网页不能嵌入
X-Frame-Options: ALLOW-FROM http://s3131212.com
只允许指定网页的iframe请求,不过兼容性较差Chrome不支持
X-Frame-Options
其实就是将前端 js 对 iframe 的把控交给服务器来进行处理
// js
if (window != window.top) {
window.top.location.href = window.location.href;
}
// 等价于
X-Frame-Options: DENY
// js
if (top.location.hostname != window.location.hostname) {
top.location.href = window.location.href;
}
// 等价于
X-Frame-Options: SAMEORIGIN
该属性是对页面的 iframe 进行一个主要限制,不过,涉及 iframe 的 header 可不止这一个,另外还有一个 Content Security Policy
,同样也可以对 iframe 进行限制
3、sandbox
sandbox
就是用来给指定 iframe 设置一个沙盒模型限制 iframe 的更多权限
sandbox 是h5
的一个新属性,IE10+
支持
启用方式就是使用 sandbox 属性:
<iframe sandbox src=”...”></iframe>
这样会对 iframe 页面进行一系列的限制:
-
script
脚本不能执行 - 不能发送
ajax
请求 - 不能使用本地存储,即
localStorage
,cookie
等 - 不能创建新的弹窗和
window
- 不能发送
表单
- 不能加载额外插件比如
flash
等
同时可以放宽一点权限。在 sandbox 里面进行一些简单设置:
<iframe sandbox=”allow-same-origin” src=”...”></iframe>
常用的配置有:
配置 | 效果 |
---|---|
allow-forms | 允许进行提交表单 |
allow-scripts | 运行执行脚本 |
allow-same-origin | 允许同域请求,比如 ajax,storage |
allow-top-navigation | 允许 iframe 能够主导 window.top 进行页面跳转 |
allow-popups | 允许 iframe 中弹出新窗口,比如 window.open,target=“_blank” |
allow-pointer-lock | 在 iframe 中可以锁定鼠标,主要和鼠标锁定有关 |
可以通过在 sandbox
里,添加允许进行的权限.
<iframe sandbox=”allow-forms allow-same-origin allow-scripts” src=”...”></iframe>
这样可以保证 js 脚本的执行,但是禁止 iframe 里的 javascript 执行 top.location = self.location
六、iframe 的局限
1、创建比一般的 DOM 元素慢了 1-2 个数量级
iframe
的创建比其它包括 scripts
和 css
的 DOM
元素的创建慢了 1-2 个数量级
,使用 iframe 的页面一般不会包含太多 iframe,所以创建 DOM 节点所花费的时间不会占很大的比重。但带来一些其它的问题:onload
事件以及连接池(connection pool
)
2、阻塞页面加载
及时触发 window 的 onload
事件是非常重要的。onload 事件触发使浏览器的 “忙” 指示器停止,告诉用户当前网页已经加载完毕。当 onload 事件加载延迟后,它给用户的感觉就是这个网页非常慢。
window 的 onload 事件需要在所有 iframe 加载完毕后(包含里面的元素)才会触发。在 Safari
和 Chrome
里,通过 JavaScript 动态设置 iframe 的 SRC
可以避免这种阻塞情况
3、唯一的连接池
浏览器只能开少量的连接到 web
服务器。比较老的浏览器,包含 Internet Explorer 6 & 7
和 Firefox 2
,只能对一个域名(hostname
)同时打开2个连接。这个数量的限制在新版本的浏览器中有所提高。Safari 3+
和 Opera 9+
可同时对一个域名打开 4 个连接,Chrome 1+
, IE 8
以及 Firefox 3
可以同时打开 6 个。
绝大部分浏览器,主页面和其中的 iframe 是共享这些连接的。这意味着 iframe 在加载资源时可能用光了所有的可用连接,从而阻塞了主页面资源的加载
。如果 iframe 中的内容比主页面的内容更重要,这当然是很好的。但通常情况下,iframe 里的内容是没有主页面的内容重要的。这时 iframe 中用光了可用的连接就是不值得的了。一种解决办法是,在主页面上重要的元素加载完毕后,再动态设置 iframe 的 src
。
4、不利于 SEO
搜索引擎的检索程序无法解读 iframe。
另外,iframe 本身不是动态语言,样式和脚本都需要额外导入。综上,iframe 应谨慎使用。
七、iframe 的实战指南
在实际开发中,我们常常需要用到 iframe
技术,下面列出了一些相关建议供您参考:
- 如果需要通过 iframe 加载同一站点内的内容,可以使用
Ajax
来替代。 - 不建议使用 iframe 来让
搜索引擎
索引,因为嵌入的页面内容在外部不能被内容索引器抓取到。 - 如果嵌入的页面属于
第三方站点
,需要注意身份验证
等安全问题。 - 对于一些特定的应用场景,如展示
Canvas
、SVG
等动态效果或使用WebGL
进行图形渲染
,可以使用到 iframe。
总结
<iframe>
元素有着广泛的使用场景。它的优点在于,能够将一个网页嵌入到另一个网页中,实现更丰富的交互和用户体验;同时,使用postMessage()
等方法,可以实现父子窗口之间的通信。但<iframe>
元素也有缺点,在跨域访问和移动设备性能等方面存在一些问题。在实际应用中,需要根据具体情况来确定是否要使用<iframe>
,并合理地选择解决方案。