zoukankan      html  css  js  c++  java
  • rem实现移动端自适应页面

    一、把px转换成rem方案

    1、cssrem插件

    2、css预处理器

    3、rem-unit插件

    4、px2rem插件

    rem就是相对于根元素的font-size来做计算,设置好根结点字体大小,子节点用rem做单位,实现自适应。

    二、动态改变字体大小方案

    1、css方案之媒体查询

    设置html的font-size

    @media screen and (min- 320px) {
        html {font-size: 14px;}
    }
    @media screen and (min- 360px) {
        html {font-size: 16px;}
    }
    @media screen and (min- 400px) {
        html {font-size: 18px;}
    }
    @media screen and (min- 440px) {
        html {font-size: 20px;}
    }
    @media screen and (min- 480px) {
        html {font-size: 22px;}
    }
    @media screen and (min- 640px) {
        html {font-size: 28px;}
    }

    2、js方案A

    window.onload=function() {
        function reCalc() {
             var windowWidth = document.documentElement.clientWidth || window.innerWidth || document.body.clientWidth;
             // windowWidth = windowWidth > 750 ? 750 : windowWidth;
             var rootSize = 28 * (windowWidth / 375);
             var htmlNode = document.getElementsByTagName("html")[0];
             htmlNode.style.fontSize = rootSize + 'px';
        }
        reCalc();
        window.addEventListener('resize', reCalc, false);
    }

    3、js方案B

    !(function(doc, win) {
      var docEl = doc.documentElement,
      resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
      reCalc = function() {
        var clientWidth = docEl.clientWidth;
        if (!clientWidth) return;
        docEl.style.fontSize = 28 * (clientWidth / 375) + 'px';
      };
      if (!doc.addEventListener) return;
      win.addEventListener(resizeEvt, reCalc, false);
      doc.addEventListener('DOMContentLoaded', reCalc, false);
    })(document, window);

    4、js方案C

    设备像素比 = 物理像素 / 设备独立像素

    A、设备像素比
    通过window.devicePixelRatio来获取设备像素比,可以通过-webkit-device-pixel-ratio,-webkit-min-device-pixel-ratio和 -webkit-max-device-pixel-ratio进行媒体查询,对不同DPR的设备,做一些样式适配。
    B、物理像素
    肉眼能够看到的大小,往往不真实。
    C、设备独立像素
    一般是个绝对值,比如css像素。
    如果css边框为1px,放在iphone的retina屏(设备像素比=2)下,会以为看到的是2px。

    在此手淘方案中,为了在一些设备中,保持文本大小相同,文本大小依然用px为单位,宽高,内外边距要用rem为单位。安装pxtorem插件,写一个div,即可生成不同dpr的div样式。

    div { 
       1rem; 
      height: 0.4rem; 
      font-size: 12px; /* 默认写上dpr为1的fontSize */
    } 
    [data-dpr="2"] div { 
      font-size: 24px; 
    } 
    [data-dpr="3"] div { 
      font-size: 36px; 
    }

    该js手淘适配方案,模拟viewport,只对iOS设备进行dpr的判断,对于Android系列,始终认为其dpr为1。该手淘方案在iframe中有bug。

    • 动态改写<meta>标签;
    • 给<html>元素添加data-dpr属性,并且动态改写data-dpr的值;
    • 给<html>元素添加font-size属性,并且动态改写font-size的值。
    !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) {
        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;
      }
      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 wrap = doc.createElement("div");
          wrap.appendChild(vpMeta);
          doc.write(wrap.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);
      // 方向改变时重置
      win.addEventListener("orientationchange", function() {
        clearTimeout(timer);
        timer = setTimeout(setFontSize, 300);
      }, false);
      // 从浏览器读取缓存时触发,pageshow每次加载页面时触发。
      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 (typeof d === "string" && d.match(/rem$/)) {
            c += "px";
        }
        return c;
      };
      flexible.px2rem = function(d) {
        var c = parseFloat(d) / this.rem;    
        if (typeof d === "string" && d.match(/px$/)) {
            c += "rem";
        }
        return c;
      }
    }(window, window.lib || (window.lib = {}));

    对于不同dpr,通过上面的js运行会产生不同的meta。

    <!-- dpr = 1-->
    <meta name="viewport" content="initial-scale=scale,maximum-scale=scale,minimum-scale=scale,user-scalable=no"> 
    <!-- dpr = 2-->
    <meta name="viewport" content="initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">
    <!-- dpr = 3-->
    <meta name="viewport" content="initial-scale=0.3333333333,maximum-scale=0.3333333333,minimum-scale=0.3333333333,user-scalable=no">
  • 相关阅读:
    ES6 export
    vue-cli3实现分环境打包步骤(给不同的环境配置相对应的打包命令)
    vue.config.js
    npm install 错误 安装 chromedriver 失败的解决办法
    解决JS(Vue)input[type='file'] change事件无法上传相同文件的问题
    CSS设置浏览器滚动条样式
    ELK 性能(3) — 在 Docker 上运行高性能容错的 Elasticsearch 集群
    ELK 性能(2) — 如何在大业务量下保持 Elasticsearch 集群的稳定
    ELK 性能(1) — Logstash 性能及其替代方案
    ElasticSearch 2 (37)
  • 原文地址:https://www.cnblogs.com/camille666/p/rem_autoadapt.html
Copyright © 2011-2022 走看看