移动端h5之rem布局/px2rem

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);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容