前言
首先這個標題再詳細的說就是如何解決font-face在IE8下間歇性出現圖標字體渲染失敗的解決方案。
如果你還不知道什么是圖標字體,可以先閱讀:鏈接1,鏈接2,鏈接3
先看在IE8下的問題:
而正常的應該是這樣:
可以看到所以圖標都顯示不了,最關鍵的是還顯示出他本身的字符,這絕對是不能忍的,必須解決。
問題的原因到底是什么?
這個頁面是為了快速一覽圖標字體的頁面,這兩個截圖都是在IE8下截圖的,所以可以看到font-face不是不兼容IE8,而是間歇性的撂挑子(出問題),至於問題原因:
我猜測:是因為字體並不阻塞頁面顯示,當第一次打開頁面,字體文件沒有緩存,且字體在頁面打開后才載入進來,導致瀏覽器沒有重新渲染頁面中使用圖標字體的字符,才導致此問題出現的
1、搭建測試環境
首先要100%復現問題,確定bug原因。我是win8的開發機,用Oracle VM VirtualBox建立虛擬機,IE6 8 9各一台,現在用IE8測試
開發環境是Visual Studio 2013,把項目跑起來后,開啟Fiddler做虛擬機的代理服務器,也就是將Fiddler作為我的真實機的反向代理服務器,這樣可以讓虛擬機連接我的真實機的localhost地址,來達到遠程VS調試的功能。
當然你可以直接把web文件發布到局域網內網IP,然后虛擬機訪問,在本例中是可以的,但是那樣VS是無法使用調試(debug)功能的。
如上圖所示虛擬機成功連接真實的localhost,但目前是沒問題的,我們需要利用Fiddler來模擬網絡問題。
2、用Fiddler模擬網絡問題
猜測是字體返回過慢,所以可以利用Fiddler的 BreakPoints ,即斷點功能。
使用Fiddler-【Rules】-【Automatic Breakpoints】-【After Response】斷點功能。
啟用【After Response】即響應后斷點,即響應已經發送至服務器,服務器也將資源返回給Fiddler,此時Fiddler等待其他資源都響應完成后,再返回給瀏覽器,以人為制造上述猜想的發生場景,過程如下圖:
順便一提,在本例中使用【Before Request】也是可以的,因為對於瀏覽器而言,使用請求前斷點和響應后斷點都是一樣的。
接下來在虛擬機中的IE8按Ctrl+F5,強制所有資源均從新加載,在Fiddler中,把所有非字體資源文件都【Run to Completion】通過,轉發給瀏覽器,最后再將字體轉發給瀏覽器。
3、穩定復現
可以看到,問題又復現了:
如果此時關閉斷點,再在虛擬機中清空緩存,並按Ctrl+F5 多少次,也無法復現此問題,只要使用Fiddler斷點,就可以100%復現此問題。
問題找到了,就是后加載進來無法渲染,想辦法強制觸發渲染就可以了。
如何解決此問題?
解決方案1:加載完成后調整下瀏覽器大小
大家應該都知道,調整瀏覽器大小會造成網頁重繪與回流,會讓頁面幾乎所有元素重新繪制。因為重新繪制樣式了,所以自然也就可以了解決圖標字體渲染失敗的問題。
缺點自然不用說,這等於沒解決,不過我們可以利用重繪后圖標生效的特性來讓強制令其頁面回流重繪。
解決方案2:強制回流
既然我們要讓所有圖標字體都生效,那么最好的辦法是讓頁面發生大面積回流,以觸發整頁重新渲染。那么我們就需要先知道有哪些操作可以導致回流:
以下操作會觸發回流:
1、調整窗口大小
2、改變字體
3、增加或者移除樣式表
4、內容變化,比如用戶在input框中輸入文字
5、激活 CSS 偽類,比如 :hover (IE 中為兄弟結點偽類的激活
6、操作 class 屬性
7、腳本操作 DOM
8、計算 offsetWidth 和 offsetHeight 屬性
9、設置 style 屬性的值
10、其他會導致回流的操作
所以就有了以下失敗的嘗試:
給body頂部插入元素,設定body的寬度,設定絕對定位再設置回來,強制修改font-face的字體再改回來等等,最終解決是沒成功,如果各位有什么好辦法歡迎留言。
解決方案3:重設font-face的偽類內容
最終通過設置 !important 來覆蓋所有font-face的css,再重新應用就可以實現了。
代碼:
<style> html.fix-ie-font-face :before, html.fix-ie-font-face :after { content: none !important; }
</style> <script> //重設偽類,使字體強制生效 !(function redrawFontFace() { if ($.support.leadingWhitespace) return; $(window).one("load", function() { console.log("onload!!!!!!!!!!!"); $('html').addClass('fix-ie-font-face'); setTimeout(function() { $('html').removeClass('fix-ie-font-face'); }, 10); }); }()); </script>
原理就是先讓所有圖標字體失效,再讓他們生效,就可以了。
需要注意的一點是:必須注冊為 window 的 onload 事件。
最常用的$.ready()是不行的,他的本質是 DOMContentLoaded ,他會在DOM加載結束后就觸發,我們需要在圖標字體文件加載后再執行,因為沒有字體加載后的load事件(如果有請一定告訴我),所以必須要在整頁所有資源都加載完成后再觸發本函數。
順便附上jquery中的 $.ready 實現方法源碼:

//jquery-1.9.1.js #885 jQuery.ready.promise = function( obj ) { if ( !readyList ) { readyList = jQuery.Deferred(); // Catch cases where $(document).ready() is called after the browser event has already occurred. // we once tried to use readyState "interactive" here, but it caused issues like the one // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready setTimeout( jQuery.ready ); // Standards-based browsers support DOMContentLoaded } else if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", completed, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", completed, false ); // If IE event model is used } else { // Ensure firing before onload, maybe late but safe also for iframes document.attachEvent( "onreadystatechange", completed ); // A fallback to window.onload, that will always work window.attachEvent( "onload", completed ); // If IE and not a frame // continually check to see if the document is ready var top = false; try { top = window.frameElement == null && document.documentElement; } catch(e) {} if ( top && top.doScroll ) { (function doScrollCheck() { if ( !jQuery.isReady ) { try { // Use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // detach all dom ready events detach(); // and execute any waiting functions jQuery.ready(); } })(); } } } return readyList.promise( obj ); };
其他問題
1、IE8下圖標字體非常有鋸齒感怎么解決?如圖
解決方案:做一張1*1大小的透明PNG圖,然后給所有的圖標字體的類樣式增加IE特有的 filter 屬性,如下:
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src=images/IEfix.png, sizingMethod=crop);
zoom: 1;
增加濾鏡后效果:
圖標看上去還算說得過去,至於文字的鋸齒,不是本文探討的范圍內,辣個要去電腦中設置了。
缺點就是會降低頁面打開速度,增加頁面CPU占用量,會讓頁面變卡,當然前提是你頁面使用了太多圖標字體。
2、待補充…
代碼下載
本文代碼已托管至Github:
https://github.com/xxcanghai/cnblogsFiles/tree/master/fix-IE-bootstrap-font-face
擴展閱讀
(完)
原文地址-http://www.cnblogs.com/xxcanghai/p/5000984.html