30行js讓你的rem彈性布局適配所有分辨率(含豎屏適配)


用rem來實現移動端的彈性布局是個好主意!用法如下:

CSS
@media only screen and (max-width: 320px), only screen and (max-device-width:320px) { html { font-size:10px; } } @media only screen and (max-width: 640px), only screen and (max-device-width:640px) { html { font-size:20px; } } .test-div{width: 10rem;} 

那么這個.test-div的寬度在320px的分辨率下會是10 * 10 = 100px, 在640下是10 * 20 = 200px,從而達到了彈性縮放的目的。

但是這樣做還是有2個問題:

1. 隨着各種新手機的發布,分辨率也碎片化了,我們無法預知將來會出現的分辨率寬度,我們不可能把所有要兼容的分辨率寫到css里。

2. 這樣寫只能做到頁面適配不同的寬度,對於那種在各種屏幕上都要在一屏幕內顯示的頁面,就沒有辦法適配了。

比如這種非常流行的整屏滑動頁面,當屏幕寬高比小於設計稿的比例時會縮放:

所以完美解決適配的問題就得靠js了,思路非常簡單,判斷一下當前終端的寬度(這里在安卓上有個坑,后面會說)和設計稿寬度的比例,計算出需要縮放的倍數,然后根據這個倍數值改變html的字體大小即可。

如果需要橫豎屏都適配,那么根據終端寬高比例較小的那一個來計算。用通俗的語言來說,如果終端屏幕比設計稿更加寬矮一些,那么久根據它和設計稿的高度比例來計算字體。

思路永遠是簡單,實現永遠是有問題需要解決的,先上代碼:

https://github.com/leon776/setHtmlRem

JAVASCRIPT
console.time("test"); /* # 按照寬高比例設定html字體, width=device-width initial-scale=1版 # @pargam win 窗口window對象 # @pargam option{ designWidth: 設計稿寬度,必須 designHeight: 設計稿高度,不傳的話則比例按照寬度來計算,可選 designFontSize: 設計稿寬高下用於計算的字體大小,默認20,可選 callback: 字體計算之后的回調函數,可選 } # return Boolean; # xiaoweili@tencent.com # ps:請盡量第一時間運行此js計算字體 */ !function(win, option) { var count = 0, designWidth = option.designWidth, designHeight = option.designHeight || 0, designFontSize = option.designFontSize || 20, callback = option.callback || null, root = document.documentElement, body = document.body, rootWidth, newSize, t, self; root.style.width = 100%; //返回root元素字體計算結果 function _getNewFontSize() { var scale = designHeight !== 0 ? Math.min(win.innerWidth / designWidth, win.innerHeight / designHeight) : win.innerWidth / designWidth; return parseInt( scale * 10000 * designFontSize ) / 10000; } !function () { rootWidth = root.getBoundingClientRect().width; self = self ? self : arguments.callee; //如果此時屏幕寬度不准確,就嘗試再次獲取分辨率,只嘗試20次,否則使用win.innerWidth計算 if( rootWidth !== win.innerWidth && count < 20 ) { win.setTimeout(function () { count++; self(); }, 0); } else { newSize = _getNewFontSize(); //如果css已經兼容當前分辨率就不管了 if( newSize + 'px' !== getComputedStyle(root)['font-size'] ) { root.style.fontSize = newSize + "px"; return callback && callback(newSize); }; }; }(); //橫豎屏切換的時候改變fontSize,根據需要選擇使用 win.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function() { clearTimeout(t); t = setTimeout(function () { self(); }, 300); }, false); }(window, { designWidth: 640, designHeight: 1136, designFontSize: 20, callback: function (argument) { console.timeEnd("test") } });

然后再說幾個點和問題:1. 這段代碼對viewport有要求,必須是width=device-width initial-scale=1,即窗口的大小是設備物理寬度(分辨率 / devicePixelRatio),並且禁止縮放。另外還有一種做法就是手機淘寶的做法,窗口大小是分辨率寬度,然后縮放倍數是1/devicePixelRatio,這里暫且不討論。

2.就是解決安卓上的問題。經過實測,有些安卓機器,使用1的viewport,在頁面剛加載的時候。不管是讀取window.innerWidth,還是doc的getBoundingClientRect().width,或者是body的clientWidth,都不是設備的物理寬度。所以只好祭出黑魔法setTimeout,一試果然可以,異步100ms執行獲取屏幕寬度的代碼就准確了。但是這種不可控的代碼讓人不爽。

因為width=device-width initial-scale=1,documentElement的寬度又是100%,所以當這兩個值相等的時候我們可以認為目前獲取到的屏幕寬度是准確的。那么使用此條件作為判斷條件,不斷的setTimeout(fun(){}, 0)去判斷,當此條件為真時改變documentElement的字體。可以盡可能快的執行目標代碼。但是又萬一這兩個值一直不相等又不能無限的死循環下去,所以設置了一個嘗試上限,到上限之后用窗口寬度來計算(縮放比例不對的話用戶起碼可以看到完整的頁面)。在chrome下測試,執行40次代碼的平均時間是230ms,考慮到安卓機的js引擎速度,將上限設為了20。

3.是執行時機,個人建議將這段代碼放到head里,第一時間計算好html的fontSize,避免重繪。如果你有有一些跟獲取dom元素尺寸相關的操作,就得放到這個計算函數的回調里面了,這時候就不能放到head里(因為運行的時候dom都還沒加載),只能放到底部或者doc的ready事件里了。最佳實踐是有一個全屏的loading畫面,當fontSize計算好了之后再把真正的頁面展示出來。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM