美文网首页
web移动端UI适配之rem

web移动端UI适配之rem

作者: 七分小熊猫 | 来源:发表于2019-10-29 14:33 被阅读0次

    移动端适配大致两种,一种是百分比还有一种就是rem,这里就说说rem适配要怎么做,原理是什么。先说说为什么要做适配吧。

    为何要适配?

    众所周知,手机屏幕的尺寸是五花八门的,像素密度也是不一样的。同样是宽度5cm的屏幕,有的手机是720px,有的手机是1080px。

    那么假设设计师有个设计稿,宽度是720px的,设计稿里有张图,这张图的宽度也是720px。如果我们直接在代码里写这张图的宽度为720px,那我们在720px的手机上看则是正常的,这里我们用一个div做演示


    720px屏幕

    但是当用户的手机屏幕宽度有1080px的时候呢?看起来就会像这样


    1080px屏幕

    很显然这跟预期的不一样,所以我们需要div的尺寸跟随实际屏幕的宽度进行缩放。这时,我们的rem就刚好满足需求。

    rem(font size of the root element)是指相对于根元素的字体大小的单位。简单的说它就是一个相对单位。看到rem大家一定会想起em单位,em(font size of the element)是指相对于父元素的字体大小的单位。它们之间其实很相似,只不过一个计算的规则是依赖根元素一个是依赖父元素计算。

    简单来说,我们设定html元素的font-size等于100px时,1rem就等于100px。1 rem = 1 font-size

    所以我们只需要获取屏幕的宽度,然后根据宽度和设计稿的比例来计算html的font-size,并设置上去。
    在写代码的时候,就用rem代替px,这样就可以使div的尺寸根据html的font-size缩放了

    如何计算font-size?

    我们来做几个设定

    • 设计稿宽度为750px
    • 设计稿中有一个div,宽度也是750px
    • 理想状态(实际屏幕宽度也是750px)下html的font-size是100px,即1rem=100px

    那么,我们先手动写一下理想状态

    <!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

    一切正常,我们来把屏幕像素稍微调大一点,把屏幕宽度调成900。


    900px下的7.5rem

    由于我们没有动态调节html的font-size,所以div的宽度没有跟随变化。那么就来计算一下。

    先算出100px是设计稿的多少倍,然后再乘以实际屏幕宽度,就能算出缩放后的font-size了。
    100/750*900 = 120px
    现在把120设置上去

    html {
         font-size: 120px;
    }
    

    搞定~

    900px下的7.5rem

    好了,rem适配的基本原理你已经知道了,我们开始编码。
    新建一个flexible.js

    // designWidth:设计稿的实际宽度值,需要根据实际设置
    // maxWidth:支持缩放的最大屏幕宽度值,当屏幕宽度超过此值则按最大值进行计算,需要根据实际设置
    // 这段js的最后面有两个参数记得要设置,一个为设计稿实际宽度,一个为支持缩放的最大屏幕宽度值,例如设计稿为750,最大宽度为750,则为(750,750)
    (function(designWidth, maxWidth) {
        var doc = document
        var win = window
        var docEl = doc.documentElement
        var remStyle = document.createElement('style') // 创建一个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 设置好后才能执行 refreshRem,不然 refreshRem 会执行2次;
        refreshRem()
      
        win.addEventListener('resize', function() {
          clearTimeout(tid) // 防止执行两次
          tid = setTimeout(refreshRem, 300)
        }, false)
      
        win.addEventListener('pageshow', function(e) {
          if (e.persisted) { // 浏览器后退的时候重新计算
            clearTimeout(tid)
            tid = setTimeout(refreshRem, 300)
          }
        }, false)
      
        // 设定body的默认字体大小,如果不设置,将集成html的字体大小,而我们设置的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)
    // 这里我们输入设计稿750px,支持的最大屏幕宽度也是750px。
    

    可能有同学会问,为什么只有750px,现在手机都是1080px了。

    其实浏览器返回给js和css的px都是抽象的,是根据真实像素和ppi计算出来的,像我的小米8,1080px宽度,js获取的屏幕宽度也只有393px

    并且一定要在head元素里写 <meta name="viewport" content="width=device-width, initial-scale=1.0">
    关于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

    相关文章

      网友评论

          本文标题:web移动端UI适配之rem

          本文链接:https://www.haomeiwen.com/subject/ixswvctx.html