2021.10.13 五种移动端前端适配方案【移动端】

五种移动端前端适配方案:

  1. 百分比布局 图片比例混乱
  2. 媒体查询 即CSS3的 meida queries
  3. 以天猫首页为代表的 flex 弹性布局
  4. 以淘宝首页为代表的 rem+viewport缩放
  5. rem 方式

1. 百分比布局 图片会乱

2. 媒体查询 代码冗余

media queries 实现原理

meida queries 主要是通过查询设备的宽度 来执行不同的 css 代码。

@media screen and (max-width: 600px) { /*当屏幕尺寸小于600px时,应用下面的CSS样式*/
  /*你的css代码*/
}

比如:

@media  screen and (min-device-width: 320px)and (-webkit-min-device-pixel-ratio: 2) {
    html{
    font-size:10px;
    }
}
@media only screen and (min-device-width: 375px)and (-webkit-min-device-pixel-ratio: 2) {
  html{
  font-size:12px;
  }
}
   
@media only screen and (min-device-width: 375px)and (-webkit-min-device-pixel-ratio: 3) {
  html{
  font-size:16px;
  }
   
}
@media only screen and (min-device-width:412px) and (-webkit-min-device-pixel-ratio: 3) {
  html{
  font-size:20px;
  }
}
优缺点

在这里插入图片描述

3. Flex弹性布局 天猫

实现原理

它的viewport是固定的:
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
在这里插入图片描述

高度定死,宽度自适应,元素都采用px做单位。

随着屏幕宽度变化,页面也会跟着变化,效果就和PC页面的流体布局差不多,在哪个宽度需要调整的时候使用响应式布局调调就行(比如网易新闻),这样就实现了『适配』。

4. rem + viewport 缩放 淘宝

这也是淘宝使用的方案,根据屏幕宽度设定 rem 值,需要适配的元素都使用 rem 为单位,不需要适配的元素还是使用 px 为单位。

知识点

像素:中文全称为图像元素。是指在由一个数字序列表示的图像中的一个最小单位。像素仅仅只是分辨率的尺寸单位,而不是画质。

物理像素:显示器(手机屏幕)上最小的物理显示单位,在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值。也就是设备的像素,买电脑要要检查的坏点其实就是这个玩意。

设备独立像素:设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如css像素),然后由相关系统转换为物理像素。

CSS像素:也就是CSS中设置的10px就是

设备像素比dpr:简称dpr,某个方向上(x或者y)一个CSS像素对应多少个设备像素,在缩放比例100%的时候,设备像素和CSS像素是一样的,如果高分辨屏幕的话就可能不是一个设备像素对应一个CSS像素了

dpr = 某个方向上 (x或者y) 物理像素 / CSS像素

在js中 通过window.devicePixelRatio 获取到当前设备的dpr
在css中 通过-webkit-device-pixel-ratio,-webkit-min-device-pixel-ratio和 -webkit-max-device-pixel-ratio 进行媒体查询,做一些样式适配。

在这里插入图片描述
顺便:关于 em 和 rem
顺便: viewport 深入理解

实现原理

根节点 fontSize 根据宽度决定,viewport动态设置为1/dpr

如iphone6 plus的dpr为3, 则页面整体放大3倍, 1px(css单位)在plus下默认为3px(物理像素)
我们将viewport设置为1/3, 这样页面整体缩回原始大小。

!function(win, lib) {
  var timer,
    doc     = win.document,
    docElem = doc.documentElement,

    vpMeta   = doc.querySelector('meta[name="viewport"]'),
    flexMeta = doc.querySelector('meta[name="flexible"]'),

    dpr   = 0,
    scale = 0,

    flexible = lib.flexible || (lib.flexible = {});

  // 设置了 viewport meta
  if (vpMeta) {

    console.warn("将根据已有的meta标签来设置缩放比例");
    var initial = vpMeta.getAttribute("content").match(/initial\-scale=([\d\.]+)/);

    if (initial) {
      scale = parseFloat(initial[1]); // 已设置的 initialScale
      dpr = parseInt(1 / scale);      // 设备像素比 devicePixelRatio
    }

  }
  // 设置了 flexible Meta
  else if (flexMeta) {
    var flexMetaContent = flexMeta.getAttribute("content");
    if (flexMetaContent) {

      var initial = flexMetaContent.match(/initial\-dpr=([\d\.]+)/),
        maximum = flexMetaContent.match(/maximum\-dpr=([\d\.]+)/);

      if (initial) {
        dpr = parseFloat(initial[1]);
        scale = parseFloat((1 / dpr).toFixed(2));
      }

      if (maximum) {
        dpr = parseFloat(maximum[1]);
        scale = parseFloat((1 / dpr).toFixed(2));
      }
    }
  }

  // viewport 或 flexible
  // meta 均未设置
  if (!dpr && !scale) {
    // QST
    // 这里的 第一句有什么用 ?
    // 和 Android 有毛关系 ?
    var u = (win.navigator.appVersion.match(/android/gi), win.navigator.appVersion.match(/iphone/gi)),
      _dpr = win.devicePixelRatio;

    // 所以这里似乎是将所有 Android 设备都设置为 1 了
    dpr = u ? ( (_dpr >= 3 && (!dpr || dpr >= 3))
        ? 3
        : (_dpr >= 2 && (!dpr || dpr >= 2))
          ? 2
          : 1
      )
      : 1;

    scale = 1 / dpr;
  }

  docElem.setAttribute("data-dpr", dpr);

  // 插入 viewport meta
  if (!vpMeta) {
    vpMeta = doc.createElement("meta");

    vpMeta.setAttribute("name", "viewport");
    vpMeta.setAttribute("content",
      "initial-scale=" + scale + ", maximum-scale=" + scale + ", minimum-scale=" + scale + ", user-scalable=no");

    if (docElem.firstElementChild) {
      docElem.firstElementChild.appendChild(vpMeta)
    } else {
      var div = doc.createElement("div");
      div.appendChild(vpMeta);
      doc.write(div.innerHTML);
    }
  }

  function setFontSize() {
    var winWidth = docElem.getBoundingClientRect().width;

    if (winWidth / dpr > 540) {
      (winWidth = 540 * dpr);
    }

    // 根节点 fontSize 根据宽度决定
    var baseSize = winWidth / 10;

    docElem.style.fontSize = baseSize + "px";
    flexible.rem = win.rem = baseSize;
  }

  // 调整窗口时重置
  win.addEventListener("resize", function() {
    clearTimeout(timer);
    timer = setTimeout(setFontSize, 300);
  }, false);


  // 这一段是我自己加的
  // orientationchange 时也需要重算下吧
  win.addEventListener("orientationchange", function() {
    clearTimeout(timer);
    timer = setTimeout(setFontSize, 300);
  }, false);


  // pageshow
  // keyword: 倒退 缓存相关
  win.addEventListener("pageshow", function(e) {
    if (e.persisted) {
      clearTimeout(timer);
      timer = setTimeout(setFontSize, 300);
    }
  }, false);

  // 设置基准字体
  if ("complete" === doc.readyState) {
    doc.body.style.fontSize = 12 * dpr + "px";
  } else {
    doc.addEventListener("DOMContentLoaded", function() {
      doc.body.style.fontSize = 12 * dpr + "px";
    }, false);
  }

  setFontSize();

  flexible.dpr = win.dpr = dpr;

  flexible.refreshRem = setFontSize;

  flexible.rem2px = function(d) {
    var c = parseFloat(d) * this.rem;
    if ("string" == typeof d && d.match(/rem$/)) {
      c += "px";
    }
    return c;
  };

  flexible.px2rem = function(d) {
    var c = parseFloat(d) / this.rem;

    if ("string" == typeof d && d.match(/px$/)) {
      c += "rem";
    }
    return c;
  }
}(window, window.lib || (window.lib = {}));

5. rem实现 魅族

viewport也是固定的:

<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
宽度是设备宽度,缩放比例默认是1,不允许用户缩放

实现原理

通过以下代码来控制rem基准值(设计稿以720px宽度量取实际尺寸)

!function (d) {
    var c = d.document;
    var a = c.documentElement;
    var b = d.devicePixelRatio;
    var f;

    function e() {
      var h = a.getBoundingClientRect().width, g;
      if (b === 1) {
        h = 720
      }
      if(h>720) h = 720;//设置基准值的极限值
      g = h / 7.2;
      a.style.fontSize = g + "px"
    }

    if (b > 2) {
      b = 3
    } else {
      if (b > 1) {
        b = 2
      } else {
        b = 1
      }
    }
    a.setAttribute("data-dpr", b);
    d.addEventListener("resize", function () {
      clearTimeout(f);
      f = setTimeout(e, 200)
    }, false);
    e()
  }(window)

参考:
移动端的几种适配方案及rem dpr px font-size之间转换理解
移动端字体大小单位rem
移动端前端适配方案(总结) – 面试重点

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值