老爺車IE8如何兼容圖標字體

前言

首先這個標題再詳細的說就是如何解決font-face在IE8下間歇性出現圖標字體渲染失敗的解決方案javascript

若是你還不知道什麼是圖標字體,能夠先閱讀:連接1連接2連接3css

先看在IE8下的問題:html

image

 

正常的應該是這樣:java

image

能夠看到因此圖標都顯示不了,最關鍵的是還顯示出他自己的字符,這絕對是不能忍的,必須解決。jquery

 

問題的緣由究竟是什麼?

這個頁面是爲了快速一覽圖標字體的頁面,這兩個截圖都是在IE8下截圖的,因此能夠看到font-face不是不兼容IE8,而是間歇性的撂挑子(出問題),至於問題緣由:git

猜想:是由於字體並不阻塞頁面顯示,當第一次打開頁面,字體文件沒有緩存,且字體在頁面打開後才載入進來,致使瀏覽器沒有從新渲染頁面中使用圖標字體的字符,才致使此問題出現的github

 

一、搭建測試環境

首先要100%復現問題,肯定bug緣由。我是win8的開發機,用Oracle VM VirtualBox創建虛擬機,IE6 8 9各一臺,如今用IE8測試web

image

 

開發環境是Visual Studio 2013,把項目跑起來後,開啓Fiddler作虛擬機的代理服務器,也就是將Fiddler做爲個人真實機的反向代理服務器,這樣可讓虛擬機鏈接個人真實機的localhost地址,來達到遠程VS調試的功能。bootstrap

固然你能夠直接把web文件發佈到局域網內網IP,而後虛擬機訪問,在本例中是能夠的,可是那樣VS是沒法使用調試(debug)功能的。promise

image

如上圖所示虛擬機成功鏈接真實的localhost,但目前是沒問題的,咱們須要利用Fiddler來模擬網絡問題。

 

 二、用Fiddler模擬網絡問題

猜想是字體返回過慢,因此能夠利用Fiddler的 BreakPoints ,即斷點功能。

使用Fiddler-【Rules】-【Automatic Breakpoints】-【After Response】斷點功能。

image

 

啓用【After Response】即響應後斷點,即響應已經發送至服務器,服務器也將資源返回給Fiddler,此時Fiddler等待其餘資源都響應完成後,再返回給瀏覽器,以人爲製造上述猜測的發生場景,過程以下圖:

image

順便一提,在本例中使用【Before Request】也是能夠的,由於對於瀏覽器而言,使用請求前斷點和響應後斷點都是同樣的。

 

接下來在虛擬機中的IE8按Ctrl+F5,強制全部資源均重新加載,在Fiddler中,把全部非字體資源文件都【Run to Completion】經過,轉發給瀏覽器,最後再將字體轉發給瀏覽器。

image

 

3、穩定復現

能夠看到,問題又復現了:

image

若是此時關閉斷點,再在虛擬機中清空緩存,並按Ctrl+F5 多少次,也沒法復現此問題,只要使用Fiddler斷點,就能夠100%復現此問題。

問題找到了,就是後加載進來沒法渲染,想辦法強制觸發渲染就能夠了。

如何解決此問題?

 

解決方案1:加載完成後調整下瀏覽器大小

你們應該都知道,調整瀏覽器大小會形成網頁重繪迴流,會讓頁面幾乎全部元素從新繪製。由於從新繪製樣式了,因此天然也就能夠了解決圖標字體渲染失敗的問題。

缺點天然不用說,這等於沒解決,不過咱們能夠利用重繪後圖標生效的特性來讓強制令其頁面迴流重繪。

關於不知道什麼是迴流與重繪的同窗能夠參考:連接1連接2

 

解決方案2:強制迴流

既然咱們要讓全部圖標字體都生效,那麼最好的辦法是讓頁面發生大面積迴流,以觸發整頁從新渲染。那麼咱們就須要先知道有哪些操做能夠致使迴流:

如下操做會觸發迴流:

一、調整窗口大小

二、改變字體

三、增長或者移除樣式表

四、內容變化,好比用戶在input框中輸入文字

五、激活 CSS 僞類,好比 :hover (IE 中爲兄弟結點僞類的激活

六、操做 class 屬性

七、腳本操做 DOM

八、計算 offsetWidth 和 offsetHeight 屬性

九、設置 style 屬性的值

十、其餘會致使迴流的操做

因此就有了如下失敗的嘗試:

給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 );
};
$.ready的源碼

 

 

其餘問題

一、IE8下圖標字體很是有鋸齒感怎麼解決?如圖

image

解決方案:作一張1*1大小的透明PNG圖,而後給全部的圖標字體的類樣式增長IE特有的 filter 屬性,以下:

filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src=images/IEfix.png, sizingMethod=crop);
zoom: 1;

增長濾鏡後效果:

image

圖標看上去還算說得過去,至於文字的鋸齒,不是本文探討的範圍內,辣個要去電腦中設置了。

缺點就是會下降頁面打開速度,增長頁面CPU佔用量,會讓頁面變卡,固然前提是你頁面使用了太多圖標字體。

 

二、待補充…

 

代碼下載

本文代碼已託管至Github:

https://github.com/xxcanghai/cnblogsFiles/tree/master/fix-IE-bootstrap-font-face

 

擴展閱讀

 

一、頁面重繪和迴流以及優化

二、迴流與重繪:CSS性能讓JavaScript變慢?

三、IE8 CSS @font-face fonts only working for :before content on over and sometimes on refresh/hard refresh

四、再不知道字體圖標就落伍啦!

五、Font Awesome

(完)

原文地址-http://www.cnblogs.com/xxcanghai/p/5000984.html

相關文章
相關標籤/搜索