Chrome下iframe地址切换,渲染失败的问题
最近用我们公司的oa系统,发现了一个奇怪的bug。
简单介绍下我们oa系统的页面结构,导航部分为页面主框架,内容区是嵌入的iframe,平时操作都是在内容区中。
使用中发现,时不时会出现点击内容区的链接,页面突然不渲染的问题,具体可以看下图,点击“个人费用报销单”, 前两次都正常渲染了,第三次就不渲染了。 跳转就是用的最普通的a标签,没有特殊的地方。
经过我的一番研究发现,这并不是代码错误导致的白屏,而就是浏览器渲染错误,为什么这么说呢?主要是通过以下两点
- 看图片中的操作,虽然页面是白的,但是我点击了select的位置, option一样可以出现,代表就是渲染错误而已
- 我发现只要把浏览器窗口resize一下(或者打开开发者工具),页面就显示出来了
然后,我就根据chrome iframe render painting 等关键字,进行了一番google
因为bug已经很明确的,所以我本以为解决的过程也会很顺利,但是发现并不像我想的那样
首先我搜索到了chrome论坛上的一个帖子
里面的解决方式是,给iframe加上 { position: relative; } 就可以, 但是我试了试,不行。
然后因为是渲染的问题,心想先加个硬件加速吧 ,加句这个 { transform: translateZ(0); } 还是不行。
CSS方法不行,就想到JS了。 既然我手动 resize 浏览器后,页面就能显示出来,那我通过js来resize一下呢,说着写了一段代码。 监听iframe加载完,new一个resize的Event,手动 dispatchEvent,结果,还是没用。。
后来又转念一想,那如果我让页面load后,隐藏再显示,是不是就会触发渲染,于是就有了下面一段代码
var iframeHandle = document.getElementById('J_iframe');
iframeHandle.addEventListener('load', function() {
console.log('FIX:修复chrome浏览器渲染白屏问题')
var tagEle = iframeHandle.contentDocument.body;
if (tagEle) {
tagEle.style.visibility = 'hidden';
tagEle.style.visibility = 'visible';
结果,无效。
但其实这句话,我在控制台执行是有效的,为什么写出来无效呢?Emmm,一定是需要延迟执行页面显示的语句,于是加了一句setTimeout
var iframeHandle = document.getElementById('J_iframe');
iframeHandle.addEventListener('load', function() {
console.log('FIX:修复chrome浏览器渲染白屏问题')
var tagEle = iframeHandle.contentDocument.body;
if (tagEle) {
tagEle.style.visibility = 'hidden';
setTimeout(function(){
tagEle.style.visibility = 'visible';
}, 0)
果然,这样写之后,我反复点了很多次,就没有再出现渲染失败的问题。
但是,这句话加完后,又发现一个体验不好的点,因为页面是在onload后,隐藏,等到下一次队列,再显示。 实际测试发现,页面加载完会有一个比较明显的页面跳帧。虽然不是大问题,但是因为这段代码本来就是修复一个偶现的问题,如果这样修复,却导致每次页面load完都要掉帧,有点得不偿失,于是乎想到了 requestAnimationFrame, 我其实不需要在下一次事件循环的时候去显示页面,只需要再下一次渲染的时候去显示就好了,于是再次修改代码
var iframeHandle = document.getElementById('J_iframe');
iframeHandle.addEventListener('load', function() {
console.log('FIX:修复chrome浏览器渲染白屏问题')
var tagEle = iframeHandle.contentDocument.body;
if (tagEle) {
tagEle.style.display = 'none';
tagEle.style.visibility = 'hidden';
requestAnimationFrame(function(){