IE8网络字体iframe错误的解决方法

29

这篇博客文章(页面有点烦人)(顺便说一下,那不是我的博客)描述了我昨天在仅限于Internet Explorer 8中遇到的一个奇怪的bug。该bug涉及.EOT web字体和<iframe>元素。

我还没有深入研究这个bug的确切触发条件,但基本上是这样的:一个网页使用一个web字体,将内容加载到一个<iframe>中,以便框架使用Web字体,浏览器会使网页呈现为"失真"状态 。之前正常显示的文本突然变成了看起来很糟糕的Arial或其他东西,似乎是自动出现的。有时它会反弹回去,只有在随机用户交互(例如鼠标移动)时才会再次降级。

那篇博客文章有一个例子。需要澄清的是,被破坏的是包含页面,而不是<iframe>中的页面(至少在我的经验中是这样的)。

有人找到比博客中建议的更好的解决方法吗?博客中建议的是强制从@font-face声明的CSS <link>元素重新加载。 (我可以这样做,但这会稍微有些麻烦,并且它会强制我将字体设置移出文档的<head>,如果我记得正确,这会影响性能;我将不得不四处搜寻并找到那个小提示。)

编辑更新

好的,这里是一个测试页面。这是主要(容器)页面:

<!DOCTYPE html>
<html>
  <head>
    <style id='font_style'>
      @font-face {
        font-family: 'bold-display';
        src: url('DejaVuSans-Bold.eot');
      }
    </style>
    <style>
      .fancy { font-family: bold-display, "franklin gothic medium", "verdana", sans-serif; font-size: 32px; }
      iframe { width: 500px; height: 200px; }
      #floater {
        position: absolute;
        top: 100px; left: 100px;
        display: none;
      }
      #floater.showing {
        display: block;
      }
    </style>
    <script>
      function load() {
        var frame = document.createElement('iframe'),
          floater = document.getElementById('floater'),
          target = document.getElementById('target');

        frame.src = 'frame.html';
        target.appendChild(frame);
        floater.className += 'showing';
      }
      function unload() {
        var floater = document.getElementById('floater'),
          target = document.getElementById('target');
        target.innerHTML = '';
        floater.className = floater.className.replace(/\bshowing\b/g, '');
      }
    </script>
  </head>
  <body>
    <div class='fancy'>Hello World</div>
    <button type='button' onclick='load()'>Click Me</button>
    <div id='floater'>
      <div id='target'></div>
      <button type='button' onclick='unload()'>Close</button>
  </body>
</html>

框架页面具有相同的@font-face和虚假消息。

问题似乎与使用加载的字体列表中多于一个备用字体有关。我(出于无法解释的原因)在我的“font-family”值中添加了一些类似的更常见的字体。当我将它们改回以下内容时:

 .title { font-family: bold-display, sans-serif; }

然后问题就消失了(或者至少目前看起来是这样的)。

感谢那些帮忙的人。对于@albert,总结一下你尝试过的内容并回答,我会给你点赞 :-)


你的代码在哪里?你使用的是和那篇帖子完全一样的代码吗? - albert
好的,这是一个加载了与父页面相似CSS(包括@font-face)的页面的iframe。我可以尝试制作一个示例,但这很棘手,因为这个错误就是一个错误。(如果您看到它,那么毫无疑问,这是一个浏览器错误。) - Pointy
好的,我会看看能否进行测试。应该不太难。 - Pointy
嗯,这很奇怪。在你的测试页面上,点击“Click Me”,然后点击“Close”没有任何反应,但是点击两次“Click Me”会隐藏它并导致失去字体声明。我会进一步调查这个问题。 - LoveAndCoding
希望。在字体被卸载后再次点击“点击我”似乎会导致页面重新加载字体到DOM中。也许在这个事实中隐藏着一个解决方案。 - LoveAndCoding
显示剩余4条评论
9个回答

25

只要你的CSS文件大小合理,以下做法不会影响性能,你可以保留在中放置标签的方式,而且这样做没有问题,但实质上,你仍然在“重新加载”元素(尽管不是通过重置它们的URL来实现)。

如果要移除


天啊,我马上要试试这个。 - Pointy
@Pointy 更新1发布。已找到问题的原因。正在调查中。同时,我的样式表扫描修复方法目前似乎仍然有效,但我会看看是否能找到更好的解决方案。 - LoveAndCoding
@Pointy 我已经更新了一个应该可行的解决方案。如果对你不起作用,请告诉我。 - LoveAndCoding
1
哦,我以为我已经完成了(这是我第一次设置赏金)。不好意思,我现在点击了它。 - Pointy
尽管这对我们没有起作用 - 请参见下面我的答案 - 但它给了我一个好的方向去调查。所以,谢谢! - Geoff
显示剩余2条评论

2
如果您刚刚通过fontsquirrel.com生成了跨浏览器的@font-face语法,我认为您甚至不会遇到任何问题。您想要嵌入字体:
@font-face{
    font-family: 'DejaVuSansBook';
    src: url('DejaVuSans-webfont.eot'); /* ie9 compat mode */
    src: url('DejaVuSans-webfont.eot?#iefix') format('eot'),  /* ie 6-7-8 */
         url('DejaVuSans-webfont.woff') format('woff'), /* modern browsers */
         url('DejaVuSans-webfont.ttf') format('truetype'), /* Safari, Android, iOS */
         url('DejaVuSans-webfont.svg#webfontLXhJZR1n') format('svg'); /* Legacy iOS */
}

如果您发现语法失败,您还可以使用WebFont加载器脚本。我没有将功能与上面回答的代码进行比较(我确定它有效),Typekit和Google Fonts使用此JS来加载其字体。

1
不,这并不是真的。事实上,我确实有那种CSS。问题在于IE8的一个bug,毫无疑问。请检查其他答案和评论中提供的示例。 - Pointy
如果你确实有那个CSS,为什么不把它留在那里呢?我不明白为什么要删除针对IE的.eot。我不是说你错了,但IE8已经很老了...我认为应该有更多关于这种错误的文档。而且我从来没有遇到过使用那种语法跨浏览器出现问题的情况。只是想帮忙。 - albert
我没有移除针对IE的.eot文件。这个bug是真实存在的,但由于它只在一些不太常见的情况下发生,比如iframes等,所以实际上并没有影响到很多网站。换句话说,使用Web字体加上会来去的iframes相当罕见。 - Pointy
如果你的CSS就像这样,但是没有把它拿出来...我不知道你的意思。演示中的CSS只有一个链接在@font-face语句中,指向一个.eot文件。 - albert
1
是的,没错。问题最终被证明是由对网络字体的引用引起的。当CSS规则有类似于“font-family: the-webfont, Arial, Verdana, sans-serif;”这样的东西 - 根据我的经验,超过两个字体族名称时 - 当iframe被加载和卸载时会触发该错误。请阅读@Ktash提供的详细答案 - 它非常棒。当然我也感谢您的贡献。 - Pointy

2
我使用的解决方案是:
@font-face {
    font-family: 'NewsGothicFSMedium';
    src: url('NewsGothic-Medium-webfont.eot');
    src: url('NewsGothic-Medium-webfont.eot?#iefix')  format('embedded-opentype'),
         url('NewsGothic-Medium-webfont.woff') format('woff'),
         url('NewsGothic-Medium-webfont.ttf') format('truetype'),
         url('NewsGothic-Medium-webfont.svg#webfont') format('svg');
    font-weight: normal;
    font-style: normal;
}

@font-face {
    font-family: 'NewsGothicFSMediumIframe';
    src: url('NewsGothic-Medium-webfont.eot');
    src: url('NewsGothic-Medium-webfont.eot?#iefix')  format('embedded-opentype'),
         url('NewsGothic-Medium-webfont.woff') format('woff'),
         url('NewsGothic-Medium-webfont.ttf') format('truetype'),
         url('NewsGothic-Medium-webfont.svg#webfont') format('svg');
    font-weight: normal;
    font-style: normal;
}

然后在 iframe 的 CSS 中引用 iframe 字体系列。虽然需要额外的 CSS,但我认为这比仅使用几种字体时重新加载 CSS 更好。


你可能希望在WOFF之前放置SVG,否则在Windows上的Chrome中会看起来很糟糕。另外,我已经在做类似的事情了 :-) - Pointy
我所看到的所有内容都将svg放在最后。我错过了什么吗? - user2333923
以下是关于该问题的最近一篇文章之一:http://www.fontspring.com/blog/smoother-web-font-rendering-chrome - Pointy

2

我在研究一个与此非常相似的情况时遇到了这个问答,唯一的区别是没有任何iframe参与。只需要使用Google Web字体和大量浮动的div就足以导致IE8重新加载后以不同的方式呈现文本。阅读了这篇文章之后,问题似乎与使用多个备选字体列表有关。

问题似乎与使用带有多个备选字体的已加载字体有关。

我将CSS中的字体堆栈更改为仅包含单个备选项,这个错误消失了。

非常感谢您指引我正确的方向!


1

其他建议的解决方案对我们都不起作用,所以最终我们只能在页面加载完成前将整个页面保持隐藏状态。我们使用了以下代码实现:

<!--[if lte IE 8]>
    <style type="text/css">
        html {
            visibility: hidden;
        }
    </style>
    <script type="text/javascript">
        $(window).load(function() {
            $('html').css('visibility', 'visible');
        });
    </script>
<![endif]-->

1
这可能适用于某些页面布局,但在初始页面加载后进行动态更新可能会导致问题突然出现! - Pointy

1

我的解决方案是为IE8设置一种排版方式。例如:

general.css

@font-face {
  font-family: 'patua-one'; /PatuaOneRegular';/
  src: url('../fonts/PatuaOne-Regular-webfont.eot');
  src: url('../fonts/PatuaOne-Regular-webfont.eot?#iefix') format('embedded-opentype'),
       url('../fonts/PatuaOne-Regular-webfont.woff') format('woff'),
       url('../fonts/PatuaOne-Regular-webfont.ttf') format('truetype'),
       url('../fonts/PatuaOne-Regular-webfont.svg#PatuaOneRegular') format('svg');
  font-weight: normal;
  font-style: normal;
}

body {
    font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
}

h1,h2,h3,h4,h5,h6 {
    font-family: patua-one,Arial,Helvetica Neue,Helvetica,sans-serif;
}

<!--[if IE 8]>
    <link rel="stylesheet" type="text/css" href="ie8.css">
<![endif]-->

ie8.css

body {
    font-family: Arial;
}

h1,h2,h3,h4,h5,h6 {
    font-family: patua-one;
}

我重新格式化了你的CSS示例。有关更多帮助,请参阅如何格式化我的代码块? :-) - Martijn Pieters
是的,我同意 - 这似乎很重要。谢谢你的回答! - Pointy

1
我遇到了类似的问题,但是它是与简单的框架集而不是动态iframe有关。基于ktash的回答,这个方法将hack集中到顶层框架中,而不会影响可能在框架集周围加载的所有页面。
条件块将仅覆盖IE8的onload处理程序。
仍然偶尔会出现FOUC,但至少情况会自行纠正,而不需要用户移动。
<html>
<head>
<script>
function markFrameLoaded() { 
    // noop for the well behaved browsers of the world
}
</script>
<!--[if IE 8]>
<script>
function markFrameLoaded() {
    var frameCount = window.frames.length;
    for ( var f = 0 ; f < frameCount ; f++ ) {
        var styleCount = window.frames[f].document.styleSheets.length;
        for ( var s = 0 ; s < styleCount ; s++ ) {
            var sheet = window.frames[f].document.styleSheets[s];
            sheet.disabled = true;
            sheet.disabled = false;
        }
    }
}
</script> 
<![endif]-->
</head>
<frameset rows="*,*">
<frame src="top.html" onload="markFrameLoaded()">
<frame src="bottom.html" onload="markFrameLoaded()">
</frameset>
</html>

1

谢谢。在这种情况下,我不认为这与此有任何关系。在我的实际页面中,我正在使用IE的“保护”技术;在测试页面上,我只为IE导入EOT字体。 - Pointy
啊,好的。我读你的帖子时可能有点太快了,抱歉。我在 Facebook 应用程序的 iframe 中遇到了奇怪的字体更改行为。在第一次访问页面时,它可以正常呈现,但是在重新加载页面后,它会恢复到某个默认字体。 相当奇怪的是,它在 iframe 外设置了正确的字体,所以 Facebook 看起来完全不同 ;)在 iframe 外加载页面时,它可以在没有 ?#iefix 的情况下正常工作。 - Mattias Ottosson

1
我们遇到的问题似乎是当一个与主页面相同名称的 iframe 无法加载时(在我们的情况下是 404),IE 会(有时)卸载主页面上的字体。我们的解决方案是在被嵌入页面上重命名字体(以防字体因某种原因无法加载),并确保它正常加载。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接