淘寶flexible深度解讀

本文屬於原創文章,轉載請註明--來自桃源小盼聊技術javascript

關於flexible的第一篇介紹文章是大漠的《使用Flexible實現手淘H5頁面的終端適配》。請先閱讀這篇文章再來看本文。css

三年前看的時候就一個感受Perfect,還有這麼神奇的操做,可是深刻到原理就有點似懂非懂,向其餘同窗推薦的時候,總有些細節講不清楚。究其緣由是本身沒有深刻了解「爲何會產生這樣的解決方案?」。html

rem如何計算?

這種方案受到vw這個單位的啓發,100vw等於設備寬度,跟具體像素無關,有點相似100%。但百分比沒法解決寬高比的問題。html5

rem單位是參照根節點的font-size爲依據,因此只要根據設備寬度來除以100份,動態計算根節點的字體大小,就能hack這個vw的效果。java

1vw = (ClietWidth/100)= htmlFontSize = 1rem
複製代碼

flexible將頁面分紅了10份,爲何不像vw單位同樣是100份呢?拿iPhone4舉例,寬度爲320px,若是是100份,1rem=3.2px,目前大部分瀏覽器不支持12px如下的字體大小,因此320/12=26.67,最多能夠將頁面分紅26份,方便計算取整數10,1rem=(320/10)=32px。android

dpr有什麼用?

先看一下設備的實際像素與css像素的統計圖。瀏覽器

flexible-1

在iphone4以前沒有視網膜屏幕,一個設備像素等於一個css像素。最開始的移動端網站大可能是按照240px或320px的設計圖開發,iphone3GS就是320px,那麼在iPhone4的640px上,整個網站只能顯示一半,看起來很奇怪。就算廠商會自動縮放整個網站來適配 屏幕,也沒法解決固定像素的問題。app

flexible-2

考慮到這方面的影響,iPhone4的物理像素比(devicePixelRatio)dpr=2,將一個像素的寬度和高度都擴大二倍,手機在底層對網站進行了顯示上的放大,這樣一來屏幕對於原有的網站仍是320px。iphone

viewport的改變能帶來什麼?

這是計算rem的關鍵代碼字體

var docEl = document.documentElement
    var rem = docEl.clientWidth / 10
    docEl.style.fontSize = rem + 'px'
複製代碼

clientWidth是根元素的可視寬度,若是viewport縮放scale=1.0,那麼對於iPhone4的clientWidth=320px,若是scale=0.5,那麼clientWidth=640px,不管如何改變viewport值,rem都等於根節點可視寬度的1/10。

老版本0.3.2裏有這樣一段。

var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
    if (isIPhone) {
      // iOS下,對於2和3的屏,用2倍的方案,其他的用1倍方案
      if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
          dpr = 3;
      } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
          dpr = 2;
      } else {
          dpr = 1;
      }
    } else {
      // 其餘設備下,仍舊使用1倍的方案
      dpr = 1;
    }
    scale = 1 / dpr;
複製代碼

動態去計算scale,並不影響rem的計算,好處是解決了1px的問題,壞處是破壞了css媒介media。 老版本對android不支持高清方案,是個缺陷。

新版本2.0裏面則去掉了動態計算scale的方式,改成檢測是否支持0.5px的特性,經過添加類名hairlines來向下兼容

// detect 0.5px supports
    if (dpr >= 2) {
        var fakeBody = document.createElement('body')
        var testElement = document.createElement('div')
        testElement.style.border = '.5px solid transparent'
        fakeBody.appendChild(testElement)
        docEl.appendChild(fakeBody)
        if (testElement.offsetHeight === 1) {
            docEl.classList.add('hairlines')
        }
        docEl.removeChild(fakeBody)
    }
複製代碼

效果圖和rem計算方式的聯繫是什麼?

css裏的1rem=clientWidth/10,效果圖與設備像素計算的共同關聯是都把屏幕分紅10份,那麼iphone4效果圖裏的1rem=(640/10)=64px。 因此css的轉化基礎永遠是width/10。

結語

這篇文章主要是記錄思考爲何這樣作的解答。但願有更多的疑問來讓咱們一塊兒思考。

現在淘寶家也升級了適配方案,擁抱真正的vw。參考大漠後來的文章《再聊移動端頁面的適配》

相關文章
相關標籤/搜索