美文网首页
盘点移动端适配方案

盘点移动端适配方案

作者: learninginto | 来源:发表于2020-02-07 22:59 被阅读0次

    盘点移动端适配方案

    移动端.png

    作为开发者,在手机移动端做适配的时候会出现很多问题:最不希望用户看到的就是横向滚动条。其次是文字(图片等)的大小不能一成不变,要根据用户设备的物理像素调节大小。

    手机浏览器是把页面放在一个虚拟的"窗口"(viewport)中,通常这个虚拟的"窗口"(viewport)比屏幕宽,这样就不用把每个网页挤到很小的窗口中(<u>这样会破坏没有针对手机浏览器优化的网页的布局</u>),用户可以通过平移和缩放来看网页的不同部分。

    这就该轮到meta标签出场了。meta标签的作用是让当前viewport的宽度等于设备的宽度,同时不允许用户手动缩放。也许允不允许用户缩放,不同的网站有不同的要求,但让viewport的宽度等于设备的宽度,这个应该是大家都想要的效果,如果你不这样的设定的话,就会使用那个比屏幕宽的默认viewport,也就是说会出现横向滚动条;

    • 设置Viewport

    一个常用的针对移动网页优化过的页面的 viewport meta 标签大致如下:

    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    • width

    控制 viewport 的大小,可以指定的一个值,如 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。

    • initial-scale

    初始缩放比例,也即是当页面第一次 load 的时候缩放比例。

    • user-scalable

    用户是否可以手动缩放(默认设置为no,因为我们不希望用户放大缩小页面)

    • minimum-scale

    允许用户缩放到的最小比例(默认设置为1.0)

    • maximum-scale

    允许用户缩放到的最大比例(默认设置为1.0)

    一、rem适配

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

    正是因为它适配的标准是根元素的字体大小,而不同的手机型号对于根元素的规定不同[1],这便增加了很多不必要的判断。

    二、vw适配

    vw(viewpoint width),即视窗宽度,1vw等于视窗宽度的1%

    计算方式(以750的设计稿为准):设计图中元素固定的大小(px) * 100 / 750 => vw

    eg : 90px转化为vw : 90 * 100 / 750 => 12vw

    如果是375的设计稿需要乘以2 : 设计图中元素固定的大小(px) * 2 * 100 / 750 => vw

    不难看出,使用的时候仍需进行大量的计算。

    三、vw+rem适配

    因为vw的比例需要动态地计算,而rem做移动端布局的时候刚好需要动态地改变,因此我们只要稍加计算,将根元素的字体大小换成vw即可。

    • 640的设计稿

      320px == 100vw ; 1px == 100 / 320 == 0.3125vw ; 100px == 31.25vw;

      此时设置根元素字体大小html,body{font-size:31.25vw} , => 1rem == 100px; =>1px == 0.01rem;

      所以,根据设计稿的像素计算时,只需将px除以100即可

      计算方式:元素尺寸 / 2 / 100 = rem

      320的设计稿计算方式:元素尺寸 / 100 = rem

    • 750的设计稿

      375px == 100vw ; 1px == 100 / 375 == 0.26666vw ; 100px == 26.6666vw

      出现了小数点后除不尽的情况……为了将结果它转换成整数 120px == 32vw此时设置根元素字体大小html,body{font-size:32vw} , 计算方式也发生改变:元素尺寸 / 2 / 120 = rem

      375的设计稿计算方式:元素尺寸 / 120 = rem

    以上面的几种设计稿为例,尤其是750的设计稿居多,大多数情况下根据元素的尺寸 / 120 ,这么难以计算的数字,还是交给插件来做吧。以VScode中的cssrem为例:

    注意:配置完参数之后,重启软件

    cssrem.png

    四、flexible.js布局(推荐)

    通过flexible.js实现了rem自适应,有了flexible.js,我们就不必再为移动端各种设备兼容烦恼。通过rem与px的换算,把设计稿从px转到rem。再也不用为各种设备横行而担忧。

    rem是相对于根元素html,这样就意味着,我们只需要在根元素确定一个px字号,则可以来算出元素的宽高。1rem=16px(浏览器html的像素,可以设定这个基准值),假如浏览器的html设为64px,则下面的元素则1rem=64px来运算。

    阿里团队开源的一个库。使用flexible.js轻松搞定各种不同的移动端设备兼容自适应问题。

    1. 删除viewport的meta标签,替换为下面的JS代码

      (function (win, lib) {
          var doc = win.document;
          var docEl = doc.documentElement;
          var metaEl = doc.querySelector('meta[name="viewport"]');
          var flexibleEl = doc.querySelector('meta[name="flexible"]');
          var dpr = 0;
          var scale = 0;
          var tid;
          var flexible = lib.flexible || (lib.flexible = {});
      
          if (metaEl) {
              //        console.warn('将根据已有的meta标签来设置缩放比例');
              var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
              if (match) {
                  scale = parseFloat(match[1]);
                  dpr = parseInt(1 / scale);
              }
          } else if (flexibleEl) {
              var content = flexibleEl.getAttribute('content');
              if (content) {
                  var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
                  var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
                  if (initialDpr) {
                      dpr = parseFloat(initialDpr[1]);
                      scale = parseFloat((1 / dpr).toFixed(2));
                  }
                  if (maximumDpr) {
                      dpr = parseFloat(maximumDpr[1]);
                      scale = parseFloat((1 / dpr).toFixed(2));
                  }
              }
          }
      
          if (!dpr && !scale) {
              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;
      
          }
      
          docEl.setAttribute('data-dpr', dpr);
          if (!metaEl) {
              metaEl = doc.createElement('meta');
              metaEl.setAttribute('name', 'viewport');
              metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
              if (docEl.firstElementChild) {
                  docEl.firstElementChild.appendChild(metaEl);
              } else {
                  var wrap = doc.createElement('div');
                  wrap.appendChild(metaEl);
                  doc.write(wrap.innerHTML);
              }
          }
      
          function refreshRem() {
              var width = docEl.getBoundingClientRect().width;
      
              if (width / dpr > 768) {
                  width = 768 * dpr;
              }
              var rem = width / 7.5;
              docEl.style.fontSize = rem + 'px';
              flexible.rem = win.rem = rem;
          }
      
          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);
      
          if (doc.readyState === 'complete') {
              doc.body.style.fontSize = 12 * dpr + 'px';
          } else {
              doc.addEventListener('DOMContentLoaded', function (e) {
                  doc.body.style.fontSize = 12 * dpr + 'px';
              }, false);
          }
      
          refreshRem();
      
          flexible.dpr = win.dpr = dpr;
          flexible.refreshRem = refreshRem;
          flexible.rem2px = function (d) {
              var val = parseFloat(d) * this.rem;
              if (typeof d === 'string' && d.match(/rem$/)) {
                  val += 'px';
              }
              return val;
          }
          flexible.px2rem = function (d) {
              var val = parseFloat(d) / this.rem;
              if (typeof d === 'string' && d.match(/px$/)) {
                  val += 'rem';
              }
              return val;
          }
      
      })(window, window['lib'] || (window['lib'] = {}));
      
      
    2. 以750设计稿为准,元素尺寸 / 100 = rem ; 以375设计稿为准,元素尺寸 * 2 / 100 = rem ,因为flexble中会再除以2,所以这里乘以2将其抵消。

    参考博客1 前端开发博客


    1. 根字体大小:iPhone5s:12px iPhone6S:14px iPhone6P:16px

    相关文章

      网友评论

          本文标题:盘点移动端适配方案

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