signed

QiShunwang

“诚信为本、客户至上”

“postcss-px-to-viewport”——移动端前端适配的又一种方案

2020/12/29 12:31:21   来源:

0、前言

博主以前在做移动端的时候主要使用

    @media screen and (min-width: 1200px){     
    }

或者灵活点,会用之前一种流行已久的移动端适配方案,那就是rem,也就是会用如下代码:

    const deviceWidth = document.documentElement.clientWidth || document.body.clientWidth;
    document.querySelector('html').style.fontSize = deviceWidth / 7.5 + 'px';

这的确十分方便,也是我最喜欢的方案,参考vue项目设置活性字体(自适应字体大小)
之前,和公司前端交流的使用发现了一种新的方案,就是用viewport单位,现在viewport单位越来越受到众多浏览器的支持,
postcss-px-to-viewport,将px单位自动转换成viewport单位,用起来超级简单,postcss-px-to-viewport 文档

1、安装

在项目里使用npm或者yarn进行安装。
使用npm安装:npm install postcss-px-to-viewport --save-dev
使用yarn安装:yarn add -D postcss-px-to-viewport
更新完整版npm:npm i https://github.com/evrone/postcss-px-to-viewport --save-dev

2、配置参数

在项目的最外层新建.postcssrc.js文件,注意文件开头的“.”不可少,博主之前在使用的时候踩了坑,在.postcssrc.js文件中加入配置语句,.postcssrc.js全部内容如下,.postcssrc.js更新需要重启才会生效:

module.exports = {
    plugins: {
        autoprefixer: {}, // 用来给不同的浏览器自动添加相应前缀,如-webkit-,-moz-等等
        "postcss-px-to-viewport": {
            unitToConvert: "px", // 要转化的单位
            viewportWidth: 750, // UI设计稿的宽度
            unitPrecision: 6, // 转换后的精度,即小数点位数
            propList: ["*"], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
            viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
            fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw
            selectorBlackList: ["wrap"], // 指定不转换为视窗单位的类名,
            minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
            mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
            replace: true, // 是否转换后直接更换属性值
            exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配
            include: /Test.vue/,    //如果设置了include,那将只有匹配到的文件才会被转换
            landscape: false, // 是否处理横屏情况
            landscapeUnit: 'vw',    //横屏时使用的单位
            landscapeWidth: 568     //横屏时使用的视口宽度
        }
    }
};

相关参数解释,以下来源于官方文档:postcss-px-to-viewport中文文档

参数解释
unitToConvert(String)需要转换的单位,默认为"px"
viewportWidth(Number)设计稿的视口宽度
unitPrecision(Number)单位转换后保留的精度
propList(Array)指定转换的css属性的单位
viewportUnit(String)指定需要转换成的视窗单位
fontViewportUnit(String)指定字体需要转换成的视窗单位
selectorBlackList(Array)需要忽略的CSS选择器,不会转为视窗单位,使用原有单位
minPixelValue(Number)设置最小的转换数值,默认为1,只有大于1的值会被转换
mediaQuery(Boolean)媒体查询里的单位是否需要转换单位
replace(Boolean)是否直接更换属性值,而不添加备用属性
exclude(Array or Regexp)忽略某些文件夹下的文件或特定文件,如 ‘node_modules’
include(Array or Regexp)只有匹配到的文件才会被转换,如’src/mobile’
landscape(Boolean)是否添加根据 landscapeWidth 生成的媒体查询条件
landscapeUnit(String)横屏时使用的单位
landscapeWidth(Number)横屏时使用的视口宽度

其中,excludeinclude是可以一起设置的,将取两者规则的交集。

3、编写前端页面进行测试

<template>
    <div class="container">
        <div class="list">
            <div class="list-item" v-for="item in 5" :key="item">
                <p>实例{{item}}</p><!--v-for循环-->
            </div>
        </div>
    </div>
</template>

<style scoped lang="scss">/*博主这边使用了scss,需要事先在项目里安装好,vue-cli3.0新建项目可以手动添加,或者用一般的css写法也行*/
    *{
        margin: 0;
        padding: 0;
        list-style: none;
        outline: none;

        .container{
            padding-top: 20px;
            width: 100%;

            .list:before,.list:after{
                display: block;
                content: "";
                clear: both;
            }

            .list{
                width: 1200px;
                margin: 0 auto;

                .list-item:last-of-type{
                    margin-right: 0;
                }

                .list-item{
                    width: calc((1200px - 40px)*0.2);
                    margin-right: 10px;
                    height: 100px;
                    background: turquoise;
                    float: left;
                    border-radius: 3px;

                    p{
                        width: 100%;
                        text-align: center;
                        height: 100px;
                        line-height: 100px;
                        font-size: 20px;
                        color: white;
                    }
                }
            }
        }
    }
</style>


4、对比

4.1.1-前端页面(未设置)
在这里插入图片描述
4.1.2-前端页面(设置生效)
在这里插入图片描述
4.2.1-css样式(未设置)
在这里插入图片描述
4.2.2-css样式(设置生效)
在这里插入图片描述

5、问题与解释

1-vm相当于一个比例单位,可以理解为%,而“postcss-px-to-viewport”是以你在.postcssrc.js文件中设置的viewportWidth为基数,你在项目中设置的px为转化前值进行比例转化的,比如:viewportWidth=300,你项目中设置的字体为150px,那么转化之后就是50vm,公式 50(项目转化前值/300(b比例基数)*100vm=50(转化后值)vm。
2-“postcss-px-to-viewport”会对内联css样式,外联css样式有效,对内嵌css样式,js动态css无效。
5.2.1-内联css样式(生效)
在这里插入图片描述
在这里插入图片描述
5.2.2-外联css样式(生效)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
5.2.3-内嵌css样式(未生效)
在这里插入图片描述
在这里插入图片描述
5.2.4-js动态css(未生效)
在这里插入图片描述
在这里插入图片描述
3-官方更新产生的问题:如果你需要用到include,那一定要用第一步中的npm i https://github.com/evrone/postcss-px-to-viewport --save-dev,而不是npm install postcss-px-to-viewport --save-dev,为什么呢?
答案:include 是上个月才做的,还没有 release,但是文档已经提前更新了,所以可以先使用github仓库的代码,说白了用github仓库的可以用include,否则include无效。
解答地址:https://github.com/evrone/postcss-px-to-viewport/issues/53

6、参考

1、https://github.com/evrone/postcss-px-to-viewport/blob/master/README_CN.md
2、https://developer.aliyun.com/mirror/npm/package/postcss-px-to-viewport

7、自我拓展

“postcss-px-to-viewport”主要是用于移动端,但是博主在设置完成之后发现,我的项目不做相关设置的情况下,都会被“postcss-px-to-viewport”转化,这不是博主想要的,博主只想在移动端生效,pc端不起作用,那该怎么办呢?博主想到了以下几种方法:
1、监控屏幕宽度或者设备,对应移动端的设置移动端基数,对应pc端的设置pc端基数,也就是动态设置.postcssrc.js文件中的viewportWidth参数值,博主尝试过但没有成功,如果小伙伴们有办法解决,可以和博主交流。


2、设置配置参数中的 exclude,include。这就需要将移动端和pc端页面文件分开,设置匹配移动端生效或者设置排除pc端不生效。
在这里插入图片描述

默认不设置是生效的。

exclude: undefined, // 设置忽略文件,用正则做目录名匹配
include: undefined,    //如果设置了include,那将只有匹配到的文件才会被转换

这样设置对应的Mode.vue就不会生效。

exclude:[/Mode.vue/], // 设置忽略文件,用正则做目录名匹配
include: undefined,    //如果设置了include,那将只有匹配到的文件才会被转换

这样设置只有对应mobile文件夹下的才会生效。

exclude:undefined, // 设置忽略文件,用正则做目录名匹配
include: /mobile/,    //如果设置了include,那将只有匹配到的文件才会被转换

博主个人比较倾向与include匹配生效,只用把移动文件放在同一的文件夹下,同一配置即可。


3、设置配置参数中的mediaQuery: false, 使在媒体查询的css代码中不进行转化,也就是说我们需要将pc端样式写在@media里面,移动端放外面,参考代码

<style scoped lang="scss">
    *{
        margin: 0;
        padding: 0;
        list-style: none;
        outline: none;

        .container{
            padding-top: 20px;
            width: 100%;

            .list:before,.list:after{
                display: block;
                content: "";
                clear: both;
            }

            .list{
                width: 1200px;
                margin: 0 auto;

                .list-item:last-of-type{
                    margin-right: 0;
                }

                .list-item{
                    width: calc((1200px - 40px)*0.2);
                    margin-right: 10px;
                    height: 100px;
                    background: turquoise;
                    float: left;
                    border-radius: 3px;

                    p{
                        width: 100%;
                        text-align: center;
                        height: 100px;
                        line-height: 100px;
                        font-size: 20px;
                        color: white;
                    }
                }
            }
        }
    }

    @media screen and (min-width: 750px){
        *{
            margin: 0;
            padding: 0;
            list-style: none;
            outline: none;

            .container{
                padding-top: 20px;
                width: 100%;

                .list:before,.list:after{
                    display: block;
                    content: "";
                    clear: both;
                }

                .list{
                    width: 1200px;
                    margin: 0 auto;

                    .list-item:last-of-type{
                        margin-right: 0;
                    }

                    .list-item{
                        width: calc((1200px - 40px)*0.2);
                        margin-right: 10px;
                        height: 100px;
                        background: turquoise;
                        float: left;
                        border-radius: 3px;

                        p{
                            width: 100%;
                            text-align: center;
                            height: 100px;
                            line-height: 100px;
                            font-size: 20px;
                            color: white;
                        }
                    }
                }
            }
        }
    }

</style>


以上是博主对postcss-px-to-viewport的学习与应用情况,过程中还有许多不足,希望小伙伴们谅解,如发现问题或者博客中的错误,可与博主进行交流,谢谢大家阅读~~
——————谢谢————