移动端h5之rem布局/px2rem

作者: AkiraSun | 来源:发表于2017-07-31 14:45 被阅读1225次

    rem布局之媒体匹配

    最早的时候用的rem适配方法,通过手动设置媒体查询对不同设备进行设置font-size

    // 自适应 
    // ------------------------
    html{
      font-size: 38px;
    }
    @media only screen and (min-width: 320px) {
      html {
        font-size: 42.666px !important;
      }
    }
    @media only screen and (min-width: 360px) {
      html {
        font-size: 48px !important;
      }
    }
    @media only screen and (min-width: 375px) {
      html {
        font-size: 50px !important;
      }
    }
    @media only screen and (min-width: 414px) {
      html {
        font-size: 55.2px !important;
      }
    }
    @media only screen and (min-width: 480px) {
      html {
        font-size: 64px !important;
      }
    }
    @media only screen and (min-width: 560px) {
      html {
        font-size: 74.666px !important;
      }
    }
    @media only screen and (min-width: 640px) {
      html {
        font-size: 85.333px !important;
      }
    }
    @media only screen and (min-width: 720px) {
      html {
        font-size: 96px !important;
      }
    }
    @media only screen and (min-width: 750px) {
      html {
        font-size: 100px !important;
      }
    }
    @media only screen and (min-width: 800px) {
      html {
        font-size: 106.666px !important;
      }
    }
    @media only screen and (min-width: 960px) {
      html {
        font-size: 128px !important;
      }
    }
    

    当然这是很古老的方法,可以看出来我们的设计稿是750px的,以750为基准设置font-size为100
    我们可以看出这个方法通过人为比例计算,不能做到设备之间很好的覆盖有很大误差

    rem布局之自动设置fontsize

    所有有了下面这个根据屏幕尺寸自动设置font-size的方法,直接贴代码

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

    这段代码的大意是:
    如果页面的宽度超过了640px,那么页面中html的font-size恒为100px,否则,页面中html的font-size的大小为: 100 * (当前页面宽度 / 640)

    但是如果ui出的图是750px的你也要适当调整一下,为了方便计算也可以调整宽度
    我们以设计稿为640px为基准

    width:100px;
    width:1rem;//转换计算后为1rem
    
    iphone5-1.png iphone6-1.png

    rem布局之开阔视野

    该方案使用相当简单,把下面这段已压缩过的 原生JS(仅1kb) 放到 HTML 的 head 标签中即可(注:不要手动设置viewport,该方案自动帮你设置)

    <script>!function(e){function t(a){if(i[a])return i[a].exports;var n=i[a]={exports:{},id:a,loaded:!1};return e[a].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=window;t["default"]=i.flex=function(e,t){var a=e||100,n=t||1,r=i.document,o=navigator.userAgent,d=o.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i),l=o.match(/U3\/((\d+|\.){5,})/i),c=l&&parseInt(l[1].split(".").join(""),10)>=80,p=navigator.appVersion.match(/(iphone|ipad|ipod)/gi),s=i.devicePixelRatio||1;p||d&&d[1]>534||c||(s=1);var u=1/s,m=r.querySelector('meta[name="viewport"]');m||(m=r.createElement("meta"),m.setAttribute("name","viewport"),r.head.appendChild(m)),m.setAttribute("content","width=device-width,user-scalable=no,initial-scale="+u+",maximum-scale="+u+",minimum-scale="+u),r.documentElement.style.fontSize=a/2*s*n+"px"},e.exports=t["default"]}]);  flex(100, 1);</script>
    

    这是阿里团队的高清方案布局代码,所谓高清方案就是根据设备屏幕的DPR(设备像素比,又称DPPX,比如dpr=2时,表示1个CSS像素由2个物理像素点组成)** 动态设置 html 的font-size, 同时根据设备DPR调整页面的缩放值,进而达到高清效果**
    关于像素请进

    此方案也是默认 1rem = 100px,所以你布局的时候,完全可以按照设计师给你的效果图写各种尺寸啦。
    iphone5.png iphone6.png

    到这里大家和上面的对比应该有发现些什么,我们屏幕越大,像素越高,看到的应用越多

    源码

    'use strict';
    
    /**
     * @param {Number} [baseFontSize = 100] - 基础fontSize, 默认100px;
     * @param {Number} [fontscale = 1] - 有的业务希望能放大一定比例的字体;
     */
    const win = window;
    export default win.flex = (baseFontSize, fontscale) => {
      const _baseFontSize = baseFontSize || 100;
      const _fontscale = fontscale || 1;
    
      const doc = win.document;
      const ua = navigator.userAgent;
      const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i);
      const UCversion = ua.match(/U3\/((\d+|\.){5,})/i);
      const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80;
      const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);
      let dpr = win.devicePixelRatio || 1;
      if (!isIos && !(matches && matches[1] > 534) && !isUCHd) {
        // 如果非iOS, 非Android4.3以上, 非UC内核, 就不执行高清, dpr设为1;
        dpr = 1;
      }
      const scale = 1 / dpr;
    
      let metaEl = doc.querySelector('meta[name="viewport"]');
      if (!metaEl) {
        metaEl = doc.createElement('meta');
        metaEl.setAttribute('name', 'viewport');
        doc.head.appendChild(metaEl);
      }
      metaEl.setAttribute('content', `width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}`);
      doc.documentElement.style.fontSize = `${_baseFontSize / 2 * dpr * _fontscale}px`;
    };
    

    看到大漠写了一种关于viewport-vw-vh的适配方法,大家也可以看看相关资料
    Viewport移动端适配

    rem布局之px2rem

    我们在写rem布局的时候发现,尽管我们设置了基准font-size,但是我们还是要去换选一下,有没有办法直接写px,让他自动换算成rem
    有这样的需求当然我们也有解决方案

    px2rem的原理:
    px2rem.png
    官方例子 https://www.npmjs.com/package/postcss-px2rem
    • gulp脚手架下

    安装gulp-px2rem-plugin模块

    npm install gulp-postcss --save-dev
    

    gulpfile.js文件内处理

    var gulp = require('gulp');
    var postcss = require('gulp-postcss');
    var px2rem = require('postcss-px2rem');
     
    gulp.task('default', function() {
      var processors = [px2rem({remUnit: 75})];
      return gulp.src('./src/*.css')
        .pipe(postcss(processors))
        .pipe(gulp.dest('./dest'));
    });
    
    • vue-webpack下面
      webpack官方有简单举例
    npm install postcss-loader --save-dev
    
    var px2rem = require('postcss-px2rem');
     
    module.exports = {
      module: {
        loaders: [
          {
            test: /\.css$/,
            loader: "style-loader!css-loader!postcss-loader"
          }
        ]
      },
      postcss: function() {
        return [px2rem({remUnit: 75})];
      }
    }
    

    以下举例vue的写法,vue中以上webpack写法加载出错

    在webpack.base中先处理css和postcss

    {
              test: /\.(css|scss)$/,
              loader:"style-loader!css-loader!sass-loader!postcss-loader"
          }
    

    我们对px2rem写入vue-loader中

    vue-px2rem.png
    var utils = require('./utils')
    var config = require('../config')
    var isProduction = process.env.NODE_ENV === 'production'
    
    module.exports = {
      //使用px-rem转换
      postcss: [require('postcss-px2rem')({remUnit: 100})],
      loaders: utils.cssLoaders({
        sourceMap: isProduction
          ? config.build.productionSourceMap
          : config.dev.cssSourceMap,
        extract: isProduction
      })
    }
    
    

    关于1px转换

    这样一切看上去如此完美了,但是又有个大问题需要注意——1px的边框在转化为rem时,在andriod webview以及部分低版本ios webview 会看不到。处理方法——让1px在编译后,依然是1px
    使用postcss-px2rem插件处理px时候,需要在使用时候注意每个属性后面的分号不能省略,默认是都转换为rem,

    如若某个属性不需要转换为rem,需要按照dpr不同而分别设置大小,则在后面加上注释/px/,

    如若需要原样输出,则在后面加上注释/no/,此处需要多加留意,对于刚接触的我们新手来说,是个坑啊!

    .border_style{
        border-color: @border_color;
        border-style: solid;
        border-width: 1px;/*no*/
    }
    

    我们知道现在iphone大多数型号都用上了retina屏,而retina屏的分辨率相较于普通屏幕增加了一倍,也就是说原来1个像素宽度的区域内可以塞进2个像素了。我们css写的1px是一个概念像素,在retina屏的实际设备上占了2px的位置。

    而对于手机屏幕整体来说,一个标注了750宽的手机(iPhone6)在css中只需要375px就能表示
    scale缩放

    全能型写法
    @media (-webkit-min-device-pixel-ratio: 2){
      .border-bottom::after {
         border-bottom-width: 1px;
      }
      .border:after {
        content: ' ';
        display: block;
        position: absolute;
        top: 0;
        right: -100%;
        bottom: -100%;
        left: 0;
        border: 0 solid #e1e1e1;
        -webkit-transform-origin: 0 0;
        transform-origin: 0 0;
        pointer-events: none;
        -webkit-transform: scale(.5);
        transform: scale(.5);
        width: 200%;
        -webkit-box-sizing: border-box;
        box-sizing: border-box;
       }
    }
     
    满足一般需求可以使用这个
    @media (-webkit-min-device-pixel-ratio: 2)
    .border:after {
        height: 1px;
        content: '';
        width: 100%;
        border-top: 1px solid #e1e1e1;
        position: absolute;
        bottom: -1px;
        right: 0;
        transform: scaleY(0.5);
        -webkit-transform: scaleY(0.5);
    }
    

    相关文章

      网友评论

      • frostbelt1987:如何设置某个 .vue 下的所有 px 不转 rem ?
      • d4a41519402c:我的vue文件里css中使用/*no*/不起作用,请问是为什么?

      本文标题:移动端h5之rem布局/px2rem

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