ie兼容響應式布局的實現總結

雖然說響應式設計的理想狀態是,需對pc/移動各種終端進行響應;但是現實是高分辨率的pc端與手機終端屏幕相差太大,像電商這樣有大量圖片和文字 信息的同時排版要求精準的頁面,設計一個同時適應高分辨率pc又適合小尺寸的手機終端是挑戰;同時高分辨率下pc頁面信息量巨大,對于手機端用戶是否需 要,也許會造成帶寬浪費;再者手機終端和pc終端的用戶操作習慣也相差甚大,這種多圖多信息量要求精準的頁面,設計出來恐怕會是2個完全不同的版本,也許 各自維護更方便。由于業務形態原因,隨著用戶分辨率的提高,1024×768已不再是主流,寬屏用戶比例越來越大,因此我們的響應式考慮如何充分利用PC 用戶設備上更多空間而設計。下圖為淘寶用戶的屏幕分辨率和瀏覽器比例,鑒于ie8-瀏覽器目前占比約70%,media query的ie8-兼容迫于現實還是要做,淚……

media query簡介

miedia query有2種引入方式:

1.link標簽方式

<link type="text/css" media="screen" href="sans-serif.css">
<link type="text/css" media="print" href="serif.css">

2.css方式

@media screen {  * { font-family: sans-serif } }

媒體類型有很多種:‘aural’, ‘braille’, ‘handheld’, ‘print’, ‘projection’, ‘screen’, ‘tty’, ‘tv’、‘embossed’、 ‘speech’、’3d-glasses’,但最常用的是screen和print,對于前端們來講最常用的應該只有screen了。應用于所有媒體類 型可以用all,省略不寫默認就是all。media query支持很多表達式,常用的如下,完整的查看這里:

@media all and (min-width: 400px) and (max-width: 700px) { } 
@media all and (orientation: portrait) {  } 
@media and (min-device-width: 800px) { }

利用media query可以輕松實現不同屏幕寬度時切換不同的頁面布局,但是很不幸ie8及以下都還不支持media query,于是開始了下面的media query兼容之旅……

目前實現media query ie兼容的庫比較成熟的有respond.js和css3-mediaqueries-js;它們各有優劣,respond.js 壓縮后1k,只實現了media query中最常用的min-width max-width的兼容;css3-mediaqueries-js基本實現了所有css3規范中的media query特性的兼容,所以導致壓縮有16k,測試反饋其性能遠低于respond.js;不過確實一淘首頁2次響應式設計均只需用到max-width 和min-width,Modernizr 和 H5BP 也均推薦使用respond.js,下面具體看看它們的實現吧

respond.js源碼分析

使用方式

官方demo地址:http://scottjehl.github.com/Respond/test/test.html

  1. 在css中正常用 min/max-width media queries

    @media screen and (min-width: 480px) {     ...styles for 480px and up go here   
    }
    
  2. 引入respond.min.js,但要在css的后面(越早引入越好,在ie下面看到頁面閃屏的概率就越低,因為最初css會先渲染出來,如果 respond.js加載得很后面,這時重新根據media query解析出來的css會再改變一次頁面的布局等,所以看起來有閃屏的現象)

實現思路

  • 1.把head中所有的css路徑取出來放入數組

  • 2.然后遍歷數組一個個發ajax請求

  • 3.ajax回調后僅分析response中的media query的min-width和max-width語法,分析出viewport變化區間對應相應的css塊

  • 4.頁面初始化時和window.resize時,根據當前viewport使用相應的css塊。

    window.matchMedia = window.matchMedia || (function(doc, undefined){var bool,docElem = doc.documentElement,refNode = docElem.firstElementChild || docElem.firstChild,// fakeBody required forfakeBody = doc.createElement_x('body'),div     = doc.createElement_x('div');div.id = 'mq-test-1';div.style.cssText = "position:absolute;top:-100em";fakeBody.style.background = "none";fakeBody.appendChild(div);return function(q){div.innerHTML = '-';docElem.insertBefore(fakeBody, refNode);bool = div.offsetWidth == 42;docElem.removeChild(fakeBody);return { matches: bool, media: q };};
    })(document);
    //檢測是否支持media query,檢測css是否有效的方法都差不多,創建一個元素應用該css后檢測元素寬度,然后清除該元素。
    .......
    if( !!href && isCSS && !parsedSheets[ href ] ){// selectivizr exposes css through the rawCssText expandoif (sheet.styleSheet && sheet.styleSheet.rawCssText) {//sheet.styleSheet.rawCssText看不懂,原來是方便selectivizr和respond.js聯用,http://selectivizr.com/tests/respond///selectivizr的作用是 CSS3 selectors for IE;約定將原csstext放在styleSheet的link上的擴展屬性rawCssText上;這里如果聯用selectivizr可以少次ajax請求translate( sheet.styleSheet.rawCssText, href, media );parsedSheets[ href ] = true;} else {if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base)|| href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){requestQueue.push( {href: href,media: media} );}}
    }
    .......
    其余的代碼就是ajax實現和translate media query的max-width min-width的邏輯了;可以看出這里必須依賴ajax請求css路徑才能得到css文件中的mediaquery的內容,那ajax的跨域問題就要 解決了;由于我們的靜態資源都是要放cdn的,respond.js也給出了跨域方法,即引入代理頁面。//把cross-domain/respond-proxy.html 放到cdn上
    //把cross-domain/respond.proxy.gif 放到當前域服務器上
    "http://externalcdn.com/respond-proxy.html" id="respond-proxy" rel="respond-proxy" />"/path/to/respond.proxy.gif" id="respond-redirect" rel="respond-redirect" />"/path/to/respond.proxy.js">
    這里ajax跨域實現是通過代理頁面將獲取到的css,再通過window.name通信實現;如在respond.proxy.js中function checkFrameName() {var cssText;try {cssText = iframe.contentWindow.name;var now = new Date().getTime(),useTime = now - initTime;alert('獲取css耗時:'+ useTime + 'ms');}catch (e) { }if (cssText) {……//銷毀之前用于通信的iframe,后續回調callbackcallback(cssText);}else{win.setTimeout(checkFrameName, 100);}
    }
    win.setTimeout(checkFrameName, 500);//500ms后確認內部iframe的name值是否傳遞過來,后續再更新當前viewport該用的css。
    

因為實現跨域代理的問題,初始化頁面時應用上全部css耗時較長,以下光測試從開始執行該js文件到css取回調用之前的耗時為500ms-515ms之間(每次刷新結果不一樣),ie8下測試結果如下

測試結果發現,刷新頁面后會有明顯的閃屏(以該測試demo為例,一開始頁面背景是黑色的,這是默認css中的,跨域js執行完成后分析出 media query中的該viewport尺寸下應該應用red的背景,所以又變成紅色),間隔時間為500ms以上。所以體驗不是很好,而且該場景中ajax跨 域目前已經沒有更好的實現方式,500ms間隔的閃屏避免不了。

同時因為是ajax請求css,所以會因為響應式而額外產生一個請求,好在之前css請求過一遍,這次ajax請求是讀取瀏覽器緩存中的,如下圖中fiddler的檢測結果中的第三個請求和第六個請求:

respond.js總結

  • 優點:壓縮后僅1k,不跨域時性能ok,只需引入respond.js通用易用
  • 缺點:僅支持media query的min-width和max-width(用于響應式夠用);支持跨域,雖然配置有點麻煩,實現跨域代價高而且有閃屏體驗欠佳。

css3-mediaqueries-js源碼分析

css3-mediaqueries-js官方文檔和demo都沒有,相對于respond.js css3-mediaqueries-js支持幾乎所有的media query的語法,訪問測試demo

實現邏輯

其實現邏輯和respond.js差不多,只是更加支持的media query更加全面,同時支持內聯style,支持各種寬度單位(em|ex|px|in|cm|mm|pt|pc),但是這里的初始化是在 domready后執行,為了讓用戶感覺不出頁面有閃屏(之前應用初始化樣式然后js提取media query中的樣式再覆蓋一遍)現象,這里的實現是先將html移出可視區域外,等解析完media query后再重置回來,但實際目測感覺稍有閃屏(當然這里的測試是測試body背景色,移出可視區域外不管用,當然絕大部分響應式場景是適用的),實現 如下:

// prevent jumping of layout by hiding everything before painting 先將html移出可視區域外
var docEl = document.documentElement;docEl.style.marginLeft = '-32767px';// make sure it comes back after a while 異常處理,萬一獲取mediaquery css失敗,重置回來
setTimeout(function () {docEl.style.marginTop = '';
}, 20000);……// return visibility after media queries are tested 生效后重新可見
cssHelper.addListener('cssMediaQueriesTested', function () {// force repaint in IE by changing widthif (ua.ie) {docEl.style.width = '1px';}setTimeout(function () {docEl.style.width = ''; // undo widthdocEl.style.marginLeft = ''; // undo hidevar now = new Date().getTime();var useTime = now - initTime;alert('media query生效時間:'+useTime+'ms');}, 0);// remove this listener to prevent following executioncssHelper.removeListener('cssMediaQueriesTested', arguments.callee);
});

其余實現和respond.js基本一致,也需要使用ajax,所以css3-media-queries.js本身不支持跨域,當然非要支持跨域 也可以,也可以像respond.js一樣使用代理頁面跨域即可,但也會出現閃屏的現象。還是先看看不跨域情況下,大多數人為什么選擇 respond.js,主要原因還是完美支持的media query特性導致壓縮后16K,下載和執行時間都遜于respond.js,下面是同域下在ie8的測試結果(耗時140ms而respond.js僅 15ms)

css3-mediaqueries-js總結

  • 優點:1、基本支持所有css3中的media query語法
  • 缺點:1、不支持跨域(如cdn),就算支持了跨域也存在閃屏現象;2、和respond.js對比性能較差

全局切換class

因為css/js需要放到cdn上面,需要跨域,css3-mediaqueries-js不支持跨域,respond.js支持跨域但是實現跨域 后性能較差,有閃屏體驗也差,而且配置麻煩,不方便各個業務通用。對比respond.js和css3-mediaqueries-js可知,實現響應式 應用min-width和max-width足矣;同時模擬media query的效果只需要在2個關鍵時間點根據viewport切換css(初始化頁面時和window.resize)即可。所以可以選擇切換css link,可以動態切換css塊,也可以切換class

  • 切換css link(優點:邏輯清晰;缺點:增加請求數,維護麻煩,如修改一個模塊涉及到3個尺寸的響應,至少需要改3個文件)

    "stylesheet" type="text/css" media="screen and (max-width: 990px)" href="respond750.css&uuot;>
    "stylesheet" type="text/css" media="screen and (max-width: 1200px)" href="respond990.css">
    
  • 切換內聯css塊(respond.js和css3-mediaqueries-js就是通過js分析出media query然后自動根據當前viewport切換css塊,這個理想環境下是最好的,自動分析只管寫media query,但是依賴ajax獲取css內容,跨域實現成本高體驗也不好)

  • 全局切換class(特別是初始化頁面時最好在頁面內容未開始渲染之前切換class,不然會出現像韓國naver購物頻道在寬屏時刷新效果,刷新時內容由中間向外偏),特定viewport用特殊全局class標記,響應式樣式繼承在該class下,實現大致如下:

實現方式

@media screen and (min-width: 990px) {.content {width: 990px;color: red;}
}
@media screen and (min-width: 1200px) {.content {width: 1200px;color: green;}
}
.w990 .content {width: 990px;color: red;
}
.w1200 .content {width: 1200px;color: green;
}
"w990">
"content">content

全局切換class這種方式維護也是個問題,首先是js分散2處,body最上方切換全局class,domready時 window.resize時切換class,同時響應式尺寸增加時,需要改變js判斷條件;再看css的維護,media query一份,加全局class一份相同的,維護需要同時修改2次,初期media query幾十行也能接受,但是后來改版media query幾百行,這樣維護成本就大大增加了,全局class和media query copy相同的代碼引入less解決,使用方法如下:

#channels {.w1200() {.etao-channels {padding: 170px 0 0 30px;li {margin-right: 25px;}}}.w990() {.etao-channels {padding: 25px 0 0 15px;li {margin-right: 8px;}}.w750() {.etao-channels {padding: 5px 0 0 5px;li {margin-right: 5px;}a {color: #333;}}}
}
// 這樣只需維護上面一處代碼即可
#channels > .w1200;
@media (max-width: 1119px) {#channels > .w990;
}
@media (max-width: 989px) {#channels > .w750;
}
.w990 {#channels > .w990;
}
.w750 {#channels > .w750;
}

目前一淘新首頁采用以上方法維護,支持1200px、990px、750px三個尺寸的響應,不得不承認維護成本還是偏高,歡迎各種改進建議,

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/249087.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/249087.shtml
英文地址,請注明出處:http://en.pswp.cn/news/249087.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Luogu P1471 方差

題目傳送門 開了十倍空間才過是什么鬼&#xff1f;該不會我線段樹炸了吧……細思極恐 平均數都會求&#xff0c;維護區間和&#xff0c;到時候除一下就好了。 方差的求法如下(用的Luogu的圖片) 因為要維護一個平方&#xff0c;我們可以考慮使用van♂完全平方公式將它拆開&#…

python學習day17 遞歸函數

遞歸函數 http://www.cnblogs.com/Eva-J/articles/7205734.html def age(n):if n 4:return 40elif n >0 and n < 4:return age(n1) 2print(age(1)) # 46 只要寫遞歸函數&#xff0c;必須要有結束條件。 二分法查找 l [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,5…

2018年最好用的20個Bootstrap網站模板

Bootstrap是目前最受歡迎也是最簡潔的建站方式之一&#xff0c;尤其是伴隨移動端的發展&#xff0c;響應式設計已經毫無疑問成為了網頁設計的趨勢&#xff0c;網站建設要求兼容手機端已經是一種剛需&#xff0c;也成為提升用戶體驗的一種必要方式。但這無疑會加大設計師和前端人…

bit、byte、位、字節、漢字、字符之間的區別

package com.suypower.chengyu.test; public class ByteTest { /** * byte 8 bits -128 - 127 * 1 bit 1 二進制數據 * 1 byte 8 bit * 1 字母 1 byte 8 bit(位) * 1 漢字 2 byte 16 bit */ public static void main(String[] args) { // TODO Auto-generated method st…

Android SDK 2.3/3.0/4.0/4.2 下載與安裝教程

Eclipse下搭建Android開發環境教程&#xff1a;http://dev.son1c.com/show/1253.html Google已經發布了Android SDK 4.2版本.下面給朋友們介紹一下安裝 Android 模擬器 Emulator模擬器的方法: 1、首先確定安裝了Java JDK&#xff0c;如果沒有&#xff0c;可以去http://www.ora…

PMP:4.項目整合管理

內容中包含 base64string 圖片造成字符過多&#xff0c;拒絕顯示轉載于:https://www.cnblogs.com/mapanguan/p/9916902.html

瀏覽器渲染原理與過程

一、瀏覽器如何渲染網頁 要了解瀏覽器渲染頁面的過程&#xff0c;首先得知道一個名詞——關鍵路徑渲染。關鍵渲染路徑&#xff08;Critical Rendering Path&#xff09;是指與當前用戶操作有關的內容。例如用戶在瀏覽器中打開一個頁面&#xff0c;其中頁面所顯示的東西就是當前…

css框架:五大css流行框架的總結-css教程-PHP中文網

本篇文章給大家帶來的內容是關于css框架&#xff1a;五大css流行框架的總結&#xff0c;有一定的參考價值&#xff0c;有需要的朋友可以參考一下&#xff0c;希望對你有所幫助。 如今&#xff0c;CSS框架越來越受歡迎&#xff0c;可以說已經應用到每一個網站上了。作為開發工具…

第十四天

###數組&#xff1a;面向對象的方式創建&#xff1a;var arr01 new Array(1,2,3,"abc");直接創建&#xff1a;var arr02 [1,2,3,"abc"]alert (arr02.length);alert(arr02[3]);var arr03 [[1,2,3],["a","b","c","d&q…

【English Email】CIP payouts now in Workday

simplification簡化的[?s?mpl?f??ke??n] quota配額[?kwo?t?] regional區域的[?ri?d??nl] mechanics技工[m??kn?ks] annual年度的 [?nju?l] mid-year年中 [m?d j?r] bridge橋接[br?d?] Incentive激勵 [?n?sent?v] Due to the simplification of …

爬取網頁的通用代碼框架

import requests def getHTMLText(url)try:r requests.get(url,timeout30)r.raise_for_status()r.encoding r.apparent_encodingreturn r.textexcept:return "產生異常"if__name__ "__main__"url "http://www.baidu.com"print(getHTMLText(ur…

深入理解CSS盒模型 - 程序猿的程 - 博客園

深入理解CSS盒模型 本文是學習中傳思客在慕課網開的課程《前端跳槽面試必備技巧》的學習筆記。課程地址&#xff1a;https://coding.imooc.com/class/evaluation/129.html#Anchor。 如果你在面試的時候面試官讓你談談對盒模型的理解&#xff0c;你是不是不知從何談起。這種看似…

藍橋杯——機器人行走

某少年宮引進了一批機器人小車。可以接受預先輸入的指令&#xff0c;按指令行動。小車的基本動作很簡單&#xff0c;只有3種&#xff1a;左轉&#xff08;記為L&#xff09;&#xff0c;右轉&#xff08;記為R&#xff09;&#xff0c;向前走若干厘米&#xff08;直接記數字&am…

JavaWeb:腳本標識

腳本標識 一、JSP表達式 1、介紹 用于向頁面中輸出信息 2、語法格式 <% 表達式%>3、注意 在"<%"和""之間不允許有空格&#xff0c;但是在""后面的表達式之間可以有空格不僅可以插入到網頁中&#xff0c;還可以插入到HTML標記中&#xf…

線程死鎖問題

1 package com.demo.bingfa;2 3 /**4 * java并發編程中&#xff0c;死鎖的概念5 *6 * 我們啟用了兩個線程&#xff0c;分別搶占2個資源&#xff0c;但這兩個資源又分別被不同的對象&#xff08;字符串&#xff09;鎖住了。7 * 當第一個線程調用 resource1 方法&#xff0c;…

CSS的4個簡寫

CSS的4個簡寫 2010-12-13 18:50 聶微東 閱讀(1547) 評論(3) 編輯 收藏 1.background 簡寫屬性在一個聲明中設置所有的背景屬性: background-colorbackground-imagebackground-repeatbackground-attachmentbackground-position 例如: background: #444444 url(image.png…

spring boot 整合 (全)

參考: https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples轉載于:https://www.cnblogs.com/lshan/p/9924005.html

使用PM2搭建在線vue.js開發環境(以守護進程方式熱啟動)

項目以vue.jslayUI的作為前端開發技術棧&#xff0c;需要有一個在線的環境供項目成員實時查看效果&#xff0c;總不能每次都webpack打包發布后才能看到效果吧&#xff01;剛開始就簡單使用npm run dev命令熱啟動&#xff0c;但是shell命令窗口退出后&#xff0c;熱啟動也就失效…

微信小程序工具類

wechat-common-sdk ? 場景&#xff1a;目前工作中的項目需要包含并使用另一個項目。 也許是第三方庫&#xff0c;或者你獨立開發的&#xff0c;用于多個父項目的庫。 現在問題來了&#xff1a;你想要把它們當做兩個獨立的項目&#xff0c;同時又想在一個項目中使用另一個。 我…

zabbix實現mysql數據庫的監控

先來介紹zabbix中幾個常用的術語&#xff1a; 主機&#xff08;host&#xff09;&#xff1a; 要監控的網絡設備&#xff0c;可由ip或DNS名稱指定。 主機組&#xff08;host group&#xff09;&#xff1a; 主機的邏輯容器&#xff0c;可以包含主機和模板&#xff…