2021.10.11 自适应单位 rem/em【移动端】

rem 是指根元素(root element,html)的字体大小,即rem永远是基于根元素设置字体的大小来改变元素的字体大小。现代手机浏览器默认字体大小是16px
IE5+

rem

当使用 rem 单位,他们转化为像素大小取决于页根元素的字体大小,即 html 元素的字体大小。 根元素字体大小乘以你 rem 值。 例如,根元素的字体大小 16px,10rem 将等同于 160px,即 10 x 16 = 160。
IE8及更早版本外不支持rem哦

em

当使用em单位时,像素值将是em值乘以使用em单位的元素的字体大小。 例如,如果一个 div 有 18px 字体大小,10em 将等同于 180px,即 10 × 18 = 180。

使用 em 单位存在继承的时候。每个元素将自动继承其父元素的字体大小。 继承效果只能被明确的字体单位覆盖,比如px,vw 使用 em 单位的元素字体大小根据它们来定。

例:
如果我们的根元素字体大小为 16px (通常是默认值) 一个子元素 div 里面padding值为 1.5em,该 div 将从根元素继承字体大小 16px。 因此padding会翻译成 24px,即 1.5 x 16 = 24。 如果我们加多一个div来包裹原先的div,然后设置其字体大小为 1.25em呢? 我们包裹的 div 继承根元素字体大小 16px ,并乘以它自己的 1.25em 的字体大小。 这将设置包裹 div 字体大小为 20px,即 1.25 x 16 = 20。 现在我们原始的 div 不再直接从根元素继承,而是从其新的父元素继承字体大小为 20px 1.5em 其padding值现在等于 30px,即 1.5 x 20 = 30。 这个继承效应可以更复杂,如果我们向我们原始的 div 添加 em 字体单位,比方说 1.2em。 Div 从其父级继承 20px 字体大小,然后,乘以它自己的 1.2em 设置,给它 24px,即 1.2 × 20 = 24 新字体大小。 div上的1.5em padding 现在将再次改变大小,用新的字体大小,36px,即 1.5 × 24 = 36 。 最后,为了进一步说明那个 em 单位是相对于他们最终获得(不是父元素)的字体大小,让我们来看看设置padding 1.5em 如果我们显式设置 div 使用 14px值,不继承字体大小会发生什么。 现在,我们的padding为 21px,即 1.5 x 14 = 21 已经变小了。 它不受父元素的字体大小。 由于存在着这些隐患,你可以看到为什么必须知道如何正确管理使用 em 单位。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
附rem转换

!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 = {}));

MDN: 另外,不止分辨率,还涉及到DPR
移动web开发之像素和DPR详解

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值