一種讓 IE6/7/8 支持 media query 響應式設計的方法

在不一樣的瀏覽器寬度下使用不一樣的 CSS 聲明,常見的方案是使用 media query,但這個方案不支持 IE9 如下瀏覽器。css

國外比較流行的 UI 框架 bootstrap v3 版本中使用 media query 技術實現了柵格佈局 ,但要兼容 IE8 的話,( IE6/7 沒有中國佔比那麼高,因此不用兼容)須要引入 Respond.js 的方案。html

 

該方案的原理分如下 4 步:前端

一、在樣式 link 以後,載入 respond.js ,該腳本會獲取在他以前出現的 link 節點到一個數組css3

二、發送 ajax 請求從新獲取 link 數組中 css 文件文本內容git

三、經過分析文本內容中 @media 類聲明,從新計算並應用相關樣式github

四、在 window.resize 時,觸發第 3 步邏輯ajax

 

這裏的問題點有兩個:gulp

一、第 2 步是否會形成重複的請求消耗?bootstrap

二、若是 css 靜態資源存放域名與當前頁面不一樣,勢必會遇到 js 同源策略的限制,如何突破跨域問題?跨域

 

問題 1 比較好回答,基本包括 IE 在內的全部瀏覽器都會對 GET 請求進行緩存,因爲在第 1 步的時候瀏覽器已經請求過全部的 CSS 文件,所以在第 2 步 ajax 的時候會直接使用本地緩存,不會形成性能損耗。但因爲需引用一個 respond.proxy.gif 來 hack IE 路徑問題,可能會形成一個額外的請求損耗。

 

問題 2 確實存在,Respond.js 經過 iframe proxy file 的方案突破了同源策略,詳細的講解可參考這篇文章《Respond.js讓IE6-8支持CSS3 Media Query》或自行百度相關JS跨域知識。但在 Respond.js 場景中會形成兩個問題:

一、因爲 iframe 的建立是異步的,respond.proxy.js 沒法阻塞渲染,勢必會形成頁面樣式的閃動(先應用了默認樣式,第 3 步樣式分析完畢後,又從新應用一次樣式)

二、因爲 iframe proxy file 在 css 資源請求完成時的事件沒法主動回調(子iframe沒法訪問非同源父窗口),而是經過父窗口的一個定時器不斷讀取子窗口 window.name 值來實現被動通信,所以樣式的渲染就存在進一步的延遲。

 

若是使用場景沒法接收問題 2 所帶來的負面影響(有情懷的前端工程師都會把靜態資源部署到一個獨立域名,以提高網頁性能,並且也沒法接受頁面出現明顯的重繪這種體驗損失),則須要考慮其餘方案(另外 Respond.js 項目做者已經有幾年沒有維護了,部分BUG還沒修復 )。本文就此問題發散出一個基於 SASS + JS 的解決方案,以供參考。思路以下:

 

一、一般屏幕的分辨率寬度是符合必定規範的,而PC端網站柵格佈局的常見寬度是能夠窮舉的:1024px、1280px、1440px、1600px、 1920px

二、在樣式中,針對不一樣的瀏覽器寬度,咱們能夠複寫多條樣式規則,例如 body{} 、.w1280px body{} 、.w1440px body{},達到個性化的目的

三、當 window.resize 時,動態的在 html 節點上改變預設好的寬度 className ,例如寬度 width = 1620px 時,知足 width > 1600px && width < 1920px ,所以 html.classList.add('w1600px')

 

以上方法十分直觀,IE6/7/8 使用以上方案,其餘支持 media query 的瀏覽器則使用 @media only screen and (min-width: 1620px)  的 css 樣式方案。對於樣式維護性的問題(寫一大坨 @media 和 .w1440px body 之類的相一樣式確定不利於維護),咱們經過 SASS mixin 來解決,具體代碼參考如下樣式:

 

@mixin mediaWidth($min-width: 1024px, $max-width: null) {
    $widthSet: (1024px, 1280px, 1440px, 1600px, 1920px);
    $selector: ();

    @if $max-width {
        @media only screen and (min-width: $min-width) and (max-width: $max-width){ 
            @content; 
        }
    } @else {
        @media only screen and (min-width: $min-width) {
            @content; 
        }
    }

    @each $item in $widthSet {
        @if $max-width {
            @if $item >= $min-width and $item < $max-width {
                $selector: append($selector, unquote('.w#{$item} &'), 'comma');
            }
        } @else {
            @if $item >= $min-width{
                $selector: append($selector, unquote('.w#{$item} &'), 'comma');
            }
        }
    }

    #{$selector}{
        @content;
    }

}

body{
    width: 1024px;
    background-color: red;

    @include mediaWidth(1024px) {
        width: 1024px;
        background-color: orange;
    }

    @include mediaWidth(1280px, 1440px) {
        width: 1280px;
        background-color: green;
    }

    @include mediaWidth(1600px) {
        width: 1600px;
        background-color: blue;
    }

}

 

以上 SASS 編譯以後的 CSS 爲:

 

body {
    width: 1024px;
    background-color: red;
}
@media only screen and (min-width: 1024px) {
    body {
        width: 1024px;
        background-color: orange;
   }
}
.w1024px body, .w1280px body, .w1440px body, .w1600px body, .w1920px body {
    width: 1024px;
    background-color: orange;
}
@media only screen and (min-width: 1280px) and (max-width: 1440px) {
    body {
        width: 1280px;
        background-color: green;
   }
}
.w1280px body {
    width: 1280px;
    background-color: green;
}
@media only screen and (min-width: 1600px) {
    body {
        width: 1600px;
        background-color: blue;
   }
}
.w1600px body, .w1920px body {
    width: 1600px;
    background-color: blue;
}

 

問題一:若是項目中沒用到 SASS 怎麼辦?

從實際項目經驗來看,SASS 的引入能夠大幅提升樣式文件的維護性,並且不會對前端項目流程帶來任何影響,由於你能夠直接用編輯器的編譯工具在保存文件時同步編譯出 CSS 文件,例如 sublime text 的 sass build 和 build on save 插件,更不用說 sass 命令行、compass、grunt、gulp 之類的工具了。

 

問題二:若是不會 SASS 怎麼辦?

學就是了,看看這個就知道有多簡單了《SASS用法指南》。

 

以上代碼示例,參看此 demo:http://yekai.net/demo/ie-media-query.html

相關文章
相關標籤/搜索