web移動端UI適配之rem

移動端適配大致兩種,一種是百分比還有一種就是rem,這里就說說rem適配要怎么做,原理是什么。先說說為什么要做適配吧。

為何要適配?

眾所周知,手機屏幕的尺寸是五花八門的,像素密度也是不一樣的。同樣是寬度5cm的屏幕,有的手機是720px,有的手機是1080px。

那么假設(shè)設(shè)計師有個設(shè)計稿,寬度是720px的,設(shè)計稿里有張圖,這張圖的寬度也是720px。如果我們直接在代碼里寫這張圖的寬度為720px,那我們在720px的手機上看則是正常的,這里我們用一個div做演示


720px屏幕

但是當用戶的手機屏幕寬度有1080px的時候呢?看起來就會像這樣


1080px屏幕

很顯然這跟預(yù)期的不一樣,所以我們需要div的尺寸跟隨實際屏幕的寬度進行縮放。這時,我們的rem就剛好滿足需求。

rem(font size of the root element)是指相對于根元素的字體大小的單位。簡單的說它就是一個相對單位??吹絩em大家一定會想起em單位,em(font size of the element)是指相對于父元素的字體大小的單位。它們之間其實很相似,只不過一個計算的規(guī)則是依賴根元素一個是依賴父元素計算。

簡單來說,我們設(shè)定html元素的font-size等于100px時,1rem就等于100px。1 rem = 1 font-size

所以我們只需要獲取屏幕的寬度,然后根據(jù)寬度和設(shè)計稿的比例來計算html的font-size,并設(shè)置上去。
在寫代碼的時候,就用rem代替px,這樣就可以使div的尺寸根據(jù)html的font-size縮放了

如何計算font-size?

我們來做幾個設(shè)定

  • 設(shè)計稿寬度為750px
  • 設(shè)計稿中有一個div,寬度也是750px
  • 理想狀態(tài)(實際屏幕寬度也是750px)下html的font-size是100px,即1rem=100px

那么,我們先手動寫一下理想狀態(tài)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>rem適配</title>
    
</head>
<style>
    body {
        margin: 0;
        font-size: 16px;;
    }
    html {
        font-size: 100px;
    }
</style>
<body>
    <div style="width: 7.5rem;background: yellow;">
        750px/100 = 7.5rem div
    </div>
</body>
</html>

一定要寫body下的font-size=16px,或者你需要的,不然body元素下的文字默認大小就會繼承html下的100px,那樣的話,字體就太大了。

好了,來看效果


750px下的7.5rem

一切正常,我們來把屏幕像素稍微調(diào)大一點,把屏幕寬度調(diào)成900。


900px下的7.5rem

由于我們沒有動態(tài)調(diào)節(jié)html的font-size,所以div的寬度沒有跟隨變化。那么就來計算一下。

先算出100px是設(shè)計稿的多少倍,然后再乘以實際屏幕寬度,就能算出縮放后的font-size了。
100/750*900 = 120px
現(xiàn)在把120設(shè)置上去

html {
     font-size: 120px;
}

搞定~

900px下的7.5rem

好了,rem適配的基本原理你已經(jīng)知道了,我們開始編碼。
新建一個flexible.js

// designWidth:設(shè)計稿的實際寬度值,需要根據(jù)實際設(shè)置
// maxWidth:支持縮放的最大屏幕寬度值,當屏幕寬度超過此值則按最大值進行計算,需要根據(jù)實際設(shè)置
// 這段js的最后面有兩個參數(shù)記得要設(shè)置,一個為設(shè)計稿實際寬度,一個為支持縮放的最大屏幕寬度值,例如設(shè)計稿為750,最大寬度為750,則為(750,750)
(function(designWidth, maxWidth) {
    var doc = document
    var win = window
    var docEl = doc.documentElement
    var remStyle = document.createElement('style') // 創(chuàng)建一個style標簽,用于寫html樣式
    var tid //timeout句柄
  
    // 計算rem的值,即1rem等于多少px
    function refreshRem() {
      var width = docEl.getBoundingClientRect().width // 獲取屏幕寬度
      maxWidth = maxWidth || 750 // 當沒寫maxWidth時,默認maxWidth=750
      // 當屏幕寬度超過最大縮放的值,則按最大值處理,不能無限縮放,那樣會變得很大,很丑
      if (width > maxWidth) {
        width = maxWidth
      }
      // 計算html的font-size
      var rem = 100 / designWidth * width
      remStyle.innerHTML = 'html{font-size:' + rem + 'px;}'
    }
  
    // 將style標簽插入到文檔
    if (docEl.firstElementChild) {
      docEl.firstElementChild.appendChild(remStyle)
    } else {
      var wrap = doc.createElement('div')
      wrap.appendChild(remStyle)
      doc.write(wrap.innerHTML)
      wrap = null
    }
    // 要等 wiewport 設(shè)置好后才能執(zhí)行 refreshRem,不然 refreshRem 會執(zhí)行2次;
    refreshRem()
  
    win.addEventListener('resize', function() {
      clearTimeout(tid) // 防止執(zhí)行兩次
      tid = setTimeout(refreshRem, 300)
    }, false)
  
    win.addEventListener('pageshow', function(e) {
      if (e.persisted) { // 瀏覽器后退的時候重新計算
        clearTimeout(tid)
        tid = setTimeout(refreshRem, 300)
      }
    }, false)
  
    // 設(shè)定body的默認字體大小,如果不設(shè)置,將集成html的字體大小,而我們設(shè)置的100,so...
    if (doc.readyState === 'complete') {
      doc.body.style.fontSize = '16px'
    } else {
      doc.addEventListener('DOMContentLoaded', function(e) {
        doc.body.style.fontSize = '16px'
      }, false)
    }
  })(750, 750)
// 這里我們輸入設(shè)計稿750px,支持的最大屏幕寬度也是750px。

可能有同學(xué)會問,為什么只有750px,現(xiàn)在手機都是1080px了。

其實瀏覽器返回給js和css的px都是抽象的,是根據(jù)真實像素和ppi計算出來的,像我的小米8,1080px寬度,js獲取的屏幕寬度也只有393px

并且一定要在head元素里寫 <meta name="viewport" content="width=device-width, initial-scale=1.0">
關(guān)于viewport是啥,可以參閱 https://blog.csdn.net/lamanchas/article/details/78473249

最后,我們只需要在html中引用此文件即可,也可以用es6的方式引用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>rem適配</title>
    <script src="./flexible.js" type="text/javascript"></script>
    <style>
    body {
        margin: 0;
    }
    </style>
</head>
<body>
    <div style="width: 7.5rem;background: yellow;">
        750px/100 = 7.5rem div
    </div>
</body>
<script>
</script>
</html>

最后效果

25.gif
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 說到前端頁面的布局方案,可以從遠古時代的Table布局說起,然后來到 DIV+CSS布局,之后有了Float布局,...
    841只閱讀 1,559評論 1 3
  • 了解真實的『REM』手機屏幕適配rem 作為一個低調(diào)的長度單位,由于手機端網(wǎng)頁的興起,在屏幕適配中得到重用。 使用...
    張憲宇閱讀 2,320評論 0 5
  • 在移動互聯(lián)網(wǎng)快速發(fā)展的今天,手機的種類和尺寸越來越多,作為前端的小伙伴們可能會越來越頭疼,但又不得不去適配一款又一...
    keenjaan閱讀 27,206評論 9 86
  • 題外話 突然被要求教學(xué)妹怎么做移動端適配的問題,上一次我寫移動端的東西過去好久了,于是又面向百度了一波,網(wǎng)上感覺還...
    鄭虎三閱讀 697評論 0 10
  • 我們總是焦慮,抱怨生活的不公平,覺得自己就是那個最失敗的人??赡阏娴恼J真對比過嗎?你可能不知道,有多少人正羨慕著你...
    楓河閱讀 75評論 0 1

友情鏈接更多精彩內(nèi)容