移动端适配-REM 与 postcss-px-to-viewport

4,778 阅读3分钟

前言

适配移动端网页,不要忘记在 <head> 元素中添加

  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

REM

rem英文译为:font-size of the root element,意思是元素(html元素)字体大小。

1rem === html.fontSize -> true

rem关联屏幕宽度

通过js获取屏幕宽度,并将屏幕宽度赋值给html样式的fontSize属性:

// 获取屏幕宽度						
var w = document.documentElement.clientWidth;
// 设置根元素font-size						
document.documentElement.style.fontSize = w / 10 + 'px';

注:数字“10”为随意设置(将屏幕10等分),为了好计算。这个除数不宜设置太大,因为大部分浏览器的最小字体为12px。

现在可以得出:

1rem === html.fontSize === 屏幕宽度的十分之一  

因此:

10rem === 100%屏幕宽度  
1rem === 10%屏幕宽度

应用

若设计图宽度为320px(iPhone 5),上有一个宽度为160px,高为80px的<div>元素,适配过程如下。

  • 根据屏幕宽度,动态设置根元素的fontSize
window.onresize = setRootFontSize;
function setRootFontSize(){
    // 获取屏幕宽度							
    var w = document.documentElement.clientWidth;
    // 设置根元素font-size							
    document.documentElement.style.fontSize = w / 10 + 'px';
}
setRootFontSize();
  • css适配
div {
    width: 5rem;
    height: 2.5rem;
}

160px === 50%屏幕宽度 === 5rem
80px === 25%屏幕宽度 === 2.5rem

  • 测试 切换到宽度为375px(iPhone 6)屏幕下
    187.5px === 50%屏幕宽度 === 5rem
    93.75px === 25%屏幕宽度 === 2.5rem

优化

上述方式,在.css文件中需要大量的计算,非常不方便。
因此引入.scss文件,使用@function的功能来计算rem的值。

// 设计稿屏幕的宽度
$design-width: 320px;

@function px2rem($px) {
    // 计算出是几个rem
    @return $px / ($design-width / 10) + rem;
}
// 适配全局字体,设计稿默认12px
body {
    font-size: px2rem(12);
}

div {
    // 160是设计稿元素宽度
    width: px2rem(160);
    // 80是设计稿元素高度
    height: px2rem(80);
}

postcss-px-to-viewport

在node项目中,使用 postcss-px-to-viewport,自动将px转成视口单位vw。

安装

yarn add postcss-loader autoprefixer postcss-px-to-viewport --dev

postcss-loader配置

修改postcss.config.js

module.exports = {
    plugins: [
        require('autoprefixer'),
        require('postcss-px-to-viewport')({
            unitToConvert: "px", // 要转化的单位
            viewportWidth: 320, // UI设计稿的宽度
            unitPrecision: 6, // 转换后的精度,即小数点位数
            propList: ["*"], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
            viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
            fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw
            selectorBlackList: ["nav-bar", "tab-bar", "main-page-content", "swiper"], // 指定不转换为视窗单位的类名,
            minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
            mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
            replace: true, // 是否转换后直接更换属性值
            exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配
            landscape: false // 是否处理横屏情况
        })
    ]
};

propList: 当有些属性的单位我们不希望转换的时候,可以添加在数组后面,并在前面加上!号.
如 propList: ["*","!letter-spacing"],这表示:所有css属性的属性的单位都进行转化,除了.letter-spacing的选择器。

selectorBlackList:转换的黑名单,在黑名单里面的我们可以写入字符串,只要类名包含有这个字符串,就不会被匹配。
如 selectorBlackList: ['wrap'],它表示形如wrap,my-wrap,wrapper这样的类名的单位,都不会被转换。

应用


转换为:


转换为: