IE8 以下的浏览器都会出现这个问题,不致命,但非常影响页面观感。幸运的是,你不一定能遇上。
情景是,图片需要动态加载,根据给出的缩放比例调整显示大小。图片是普通 PNG,只是存放点是多样化的,同样的图片,一个以文件形式存在,另一个是保存于缓存(内存)中,前面都是用 Apache,一个读文件返回,一个做转发,用 IE 访问它们,获取其大小信息,结果竟然是不一样的。
装载图片的代码片段:
function loadImg(url, callback) { var img = new Image(); img.src = url; if (img.complete) { console.log("complete"); return callback.call(img, url); } img.onload = function() { img.onload = null; callback.call(img, url); } return img; }
要完成缩放,需要获取图片的原始大小。当然也可以用百分比数值,方案比较不是本文重点。下面写一个函数可以打印出图像对象上所有的数值属性,当然包括宽和高。
function getParam() { var arr = []; for(var i in this) { try { if (typeof this[i] !== 'number') continue; arr.push(i + ' : ' + this[i] + '\n'); } catch(e) {} // this[i] 在 IE 下有可能会报错,不影响观察,暂且忽略 } alert(arr.join('')); // 使用 alert 方便观看结果 };
然后都执行下面的,其中 testPngURL 分别为两者的 URL,这也是唯一的区别了。
preload(testPngURL, getParam);
两次执行的结果显示的 width 和 height 是不一样的,而且不成比例,而且结果是可以稳定重复的。我最纳闷的是 IE 凭什么得出另外那个错误结果的。我初时觉得可能是两次请求的 header 不一样,主要差异是存放于内存的,其响应的 Content-Type 是 application/octet-stream,文件形式的则是 image/png,内容长度是完全一样的。于是我使用 Fiddler 对内存图像的请求进行拦截,并修改其 Content-Type,结果是无效的。甚至将两者的响应头弄成完全一致,也得不到一致的结果。
暂时还没想到有什么方法可以绕过。而且最奇怪的是,有少数几个 png 的大小是正确的。难道问题出在 png 的数据上,有些隐藏的信息,但触发点到底是什么,可是敲爆头也不知道了。
虽然生产不会这么使用,但为了开发调试方便,我们会使用缓存来存放各种资源,其返回头都是非常简单而且统一的,无任何多余 header,浏览器不会自作主张做缓存。更新也方便,往同一个地址 PUT 内容即可。现在由于 IE 存在这样一个问题,其显示大小是不正确的,非常影响观感,不得不需要做些调整了。