企业IE11迁移指南:由IE11“Natural Metrics”造成的页面布局问题
2016年8月20日

升级至 IE11 后网页布局破坏最常见的原因是:IE11 使用了较新的文档模式来渲染页面。但有时候会发现一个页面即使使用了相同的文档模式,IE11 中显示的布局仍然被破坏了,这可能是由于 IE11 使用了一种全新的字体渲染模式:natural metrics,在 IE11 之前 IE 都是使用传统的gdi metrics

问题表现

下面这段网页代码是在 IE7、8 年代开发的。开发者为了将一段文字显示在一行内指定了 DIV 容器的宽度。为了保证新版本 IE 浏览器能兼容该页面,开发人员还特地使用X-UA-Compatiblemeta 标签来指定使用 IE7 文档模式。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=7" />
        <style>
            #top-box {
                background: #ccc;
                padding: 5px;
                width: 330px;
            }
        </style>
    </head>
    <body>
        <div id="top-box">
            Single line text appears in a fixed width DIV container.
        </div>
    </body>
</html>

该页面在 IE8 到 IE10 中都显示正常:

然而升级至 IE11 后,文字变成了 2 行:

问题原因

默认情况下,IE11 使用了一种叫做natural metrics的字体渲染引擎。Natural metrics使用了像素间距来提供更加适宜阅读的文字渲染效果。之前 IE 浏览器使用的字体渲染为传统的GDI metrics。从下图我们可以看出natural metrics渲染的字体更加顺滑,不像GDI metrics锯齿感那么明显。

由于之前开发是基于老版本的 IE 浏览器,330px 的宽度是基于GDI metrics计算出来的。很显然,在 natrual metrics中,330px 的宽度已经不足以将这段文字显示在一行内了。

相较于GDI metricsnatural metrics显示的每一个文字会更宽一些。我们可以通过下面的代码来测量文字:“ABC”在两种模式下的宽度。

<span id="span">ABC</span>
<br />
<button id="show-offset" onclick="showoffset()">Show offset</button>
<script>
    function showoffset() {
        alert(document.getElementById('span').offsetWidth);
    }
</script>

在 IE8 到 IE10 中(GDI metrics),“ABC”的宽度为 32。

在 IE11 中(natural metrics),“ABC”的宽度为 33。

解决方案

客户端方案

把网站加入本地 Intranet 站点。IE11 对于本地 Intranet 的站点依然使用GDI metrics来渲染字体。

代码方案

加入<meta http-equiv="X-UA-TextLayoutMetrics" content="gdi" />meta 标签以强制浏览器使用GDI metrics来渲染文字。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=7" />
        <meta http-equiv="X-UA-TextLayoutMetrics" content="gdi" />
        <style>
            #top-box {
                background: #ccc;
                padding: 5px;
                width: 330px;
            }
        </style>
    </head>
    <body>
        <div id="top-box">
            Single line text appears in a fixed width DIV container.
        </div>
    </body>
</html>

开发建议

不同的浏览器有不同的字体渲染引擎、方式。你基于一个浏览器计算得出的大小并不一定适用于另一个浏览器。所以我们尽可能不要指定文本容器的宽度,而让文本自适应于容器中,如果一定要指定宽度,那么尽量在文本周围留有一些空间避过于紧密的布局模式。

参考