先前研究 IE 內嵌 IFrame 相容模式規則時,得到一個結論

透過IFrame內嵌網頁會沿用父網頁的文件模式,透過X-UA-Compatible亦無法改變

前幾天同事回報一個黑天鵝案例:IE8 相容模式網頁內嵌 IFrame,裡面再內嵌一個 IFrame,依先前理解,兩個 IFrame 都應沿用 IE8 相容模式。實測卻發現,只要內層 IFrame 沒宣告 X-UA-Compatible,網頁會處於比 IE8 還舊的相容模式。

這引發我的好奇,莫非先前結論有誤?

工作網站還有很多需要依賴 IE 相容模式再戰十年,這些眉角不徹底弄懂,將來少不了一堆見鬼的情境。於是我設計了以下實驗:

共有 Parent.aspx、Frame.aspx、SubFrame.aspx 三個網頁。Parent.aspx 用 IFrame 內嵌 Frame.aspx,Frame.aspx 再用 IFrame 內嵌 SubFrame.aspx,三個網頁可以各自控制 X-UA-Compatible 宣告,用一小段程式偵測 X-UA-Compatible 宣告及文件模式:(寫在 ietool.js 供三個網頁共用)

var meta = document.getElementsByTagName("meta");
var ieMeta = meta.length ? meta[0].getAttribute("content").split('=')[1] : "?";
var ieMode = document.documentMode;
document.getElementById("result").innerHTML = 
    "META=" + ieMeta + ",MODE=" + ieMode;

Parent.aspx、Frame.aspx 如下,經由 QueryString 參數控制 X-UA-Compatible,並用 IFrame 內嵌下一層網頁:

<%@Page Language="C#"%>
<!DOCTYPE html>
<html>
<head>
    <%
    var p = Request["p"];
    if (!string.IsNullOrEmpty(p))
    {
    %>
    <meta http-equiv="X-UA-Compatible" content="IE=<%=p%>"/>
    <%
    }
    %>
    <style>body { font-size: 9pt; }</style>
</head>
<body>
<div style="width:520px">
    <h2>Parent</h2>
    <div id="result"></div>
    <script src="ietool.js"></script>
  <br />
  <iframe src="frame.aspx<%=Request.Url.Query%>" style="width: 300px; height: 200px">
  </iframe>
</div>
</body>

SubFrame.aspx 則多了一小段程式碼,將 Parent.aspx、Frame.aspx 與自己的 X-UA-Compatible 宣告及 IE 文件模式寫入 localStorage。

<%@Page Language="C#"%>
<!DOCTYPE html>
<html>
<head>
    <%
    var p = Request["s"];
    if (!string.IsNullOrEmpty(p))
    {
    %>
    <meta http-equiv="X-UA-Compatible" content="IE=<%=p%>"/>
    <%
    }
    %>
    <style>body { font-size: 9pt; }</style>
</head>
<body>
  <h2>Sub IFrame</h2>
    <div id="result"></div>
    <script src="ietool.js"></script>
    <script>
        var parentRes = parent.parent.document.getElementById("result").innerHTML;
        var frameRes = parent.document.getElementById("result").innerHTML;
        var subFrameRes = document.getElementById("result").innerHTML;
        var param = location.search.split("=")[4];
        localStorage[param] = parentRes + "," + frameRes + "," + subFrameRes;
    </script>
</body>

最後寫一個 TestRunner.html,三個網頁的 X-UA-Compatible 各有 Edge、10、9、8、7、5 及不指定七種選項,7x7x7 共有 343 種組合,透過程式試遍所有組合,將結果轉成 CSV 做成 Excel 報表。

<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
</head>
<body>
<button onclick="run()">Test</button><button onclick="genReport()">Report</button>
<pre id="rpt">
</pre>
<script>
    function run() {
        var list = ["Edge","10","9","8","7","5", ""];
        var jobs = [];
        for (var i = 0; i < list.length; i++) {
            for (var j = 0; j < list.length; j++) {
                for (var k = 0; k < list.length; k++) {
                    jobs.push("./parent.aspx?p=" + list[i] + "&f=" + list[j] + "&s=" + list[k] + 
                    "&n=" + (i + 1) + "-" + (j + 1) + "-" + (k + 1));
                }
            }
        }
        localStorage.clear();
        var hnd = setInterval(function() {
            if (jobs.length == 0) {
                clearInterval(hnd);
                return;
            }
            var win = window.open(jobs.pop());
            setTimeout(function() {
                win.close();
            }, 2000);
        }, 250);
    }
    function genReport() {
        var keys = Object.keys(localStorage);
        keys.sort();
        var rpt = [];
        for (var i = 0; i < keys.length; i++) {
            var p = localStorage[keys[i]].split(',');
            for (var j = 0; j < p.length; j++)
                p[j] = p[j].split('=')[1];
            rpt.push([p[0],p[2],p[4],p[1],p[3],p[5]].join(","));
        }
        document.getElementById("rpt").innerHTML = rpt.join("\n");
    }
</script>
<div>
</div>
</body>
</html>

測試過程發現: 當 Parent 為 IE8 相容模式,出現內外 IFrame 相容模式不同的狀況。重看MSDN文件的說明:

As of IE9 mode, webpages cannot display multiple document modes. For example, consider a standards-based webpage that contains a frame element that displays content in quirks mode. IE9 mode displays the child frame in standards mode (because the parent document is in standards mode). Starting with Internet Explorer 10, however, child frames can emulate quirks mode. For more info, see IEBlog: HTML5 Quirks mode in IE10. For best results, however, use document modes consistently.

IE9起,檢視網頁只允許存在一種文件模式,故IFrame網頁必須沿用父網頁的IE標準模式。IE10做了點改善,允許IFrame網頁啟用Quirks相容。

我有一個新體會,原以我以為文件說的 IE9 指的是實體瀏覽器的版本 9,但實際上用 IE11 模擬 IE9 模式就適用。結果出爐,符合新版推測:

當 Parent.aspx 為 Edge、IE=10、IE=9 時,Frame.aspx 與 SubFrame.aspx 不管 X-UA-Compatible 怎麼設定,其 IE 模式永遠與 Parent.aspx 一致。

 

當 Parent.aspx 是 IE=8、IE=7、IE=5 時,Frame.aspx、SubFrame.aspx 可隨 X-UA-Compatible 切換成不同 IE 模式,三者的 IE 模式可各自獨立,但 IE=Edge、10、9 一律降至 IE=8,當未指定 X-UA-Compatible 時,則取 IE=7。

由此新發現,先前的結論應修正為:

當父網頁為 IE11、IE10、IE9 模式,透過IFrame內嵌網頁會沿用父網頁的文件模式,透過X-UA-Compatible亦無法改變。
當父網頁為 IE8、IE7、IE5 模式,IFrame 內嵌的網頁可透過 X-UA-Compatible 切換與父網頁不同的 IE 模式,但 Edge、IE10、IE9 會降為 IE8。


Comments

# by meepo

Very good article ! It helps a lot , thank you !

Post a comment