序言
相信开发过小程序的朋友,都用过rpx
这个单位,最近项目中在开发一款小程序,而在测试阶段发现,在Pad端的元素显示过大了,完全不适应Pad端,而业务上由于Pad端的使用者还是占多数的,所以需要实现Pad端的响应式。
问题
项目中都是使用rpx
这个单位来布局的,用过这个小程序rpx
单位都知道该特性:
简单来说,就是rpx
将布局分成了750
份,根据设置rpx
的多少来布局,这样对应我们手机750的设计就很好的匹配适应,而在iPad端上,屏幕分辨率却是1536*2048
,这样导致同样在手机端显示的文字大小,在iPad端会呈现2倍的效果。
方案
针对上述问题,我们很容易想到,那是不是在iPad端时,让元素的显示的大小减去一半就行了,比如
.rule { font-size: 20rpx; } // => iPad .rule { font-size: 10rpx; }
而判断iPad端的方式有两种:
根据UA是否带有pad字样进行判断;
根据媒体查询进行判断;
针对第一种,如果需要根据UA进行判断,就需要js进行判断再插入对应的className
,这样不单每个页面都带重复写,还影响小程序性能,这样太过繁琐,所以我们采用了第二种方案。
通过媒体查询,我们在大于750px
(pad端的dpr是2,所以这里是750)的情况,将rpx
整体缩小一倍,如:
.rule { font-size: 20rpx; } // => iPad @media (min-width: 750px) { .rule { font-size: 10rpx; } }
思考
虽然问题得到解决,但是每个页面组件都单独写媒体查询,依然太过复杂,那有没有根据简单的方法?
这里我想到了利用 postcss-plugin
在编译时对样式进行修改,大概思路如下
copy一份原有的样式,将所有
rpx
对应缩小一半;再用
@media
进行包裹,并插入到原样式后面(小程序媒体查询没有权重,所以要插入原样式之后,否则插入前面会更合理);
发布
基于想法,进行实现, @hsuna/postcss-media-query-transform
便孕育而生:
安装
npm i -D @hsuna/postcss-media-query-transform yarn add -D @hsuna/postcss-media-query-transform pnpm i -D @hsuna/postcss-media-query-transform
使用
在
postcss.config.js
使用
// postcss.config.js module.exports = { plugins: [ // for example // require('autoprefixer'), require("postcss-media-query-transform")({ mediaQuery: { query: "(min-width: 750px)", scale: 0.5 }, propList: ["*"], transformUnit: "rpx", insert: "after", }), ], };
输入/输出
// input .rule { margin: 0 0 20px; font-size: 2rpx; line-height: 1.2; letter-spacing: 0.0625px; } // output .rule { margin: 0 0 20rpx; font-size: 2rpx; line-height: 1.2; letter-spacing: 0.0625rpx; } @media (min-width: 750px) { .rule { margin: 0 0 10rpx; font-size: 1rpx; letter-spacing: 0.03125px; } }
参数说明
默认
const defaultOptions = { mediaQuery: { query: "(min-width: 400px)", scale: 0.5 }, // 媒体查询及比例,允许多个 unitPrecision: 5, // 保留位数 selectorBlackList: [], // 不允许转化的选择器 propList: ["font", "font-size", "line-height", "letter-spacing"], // 需要转化的样式 transformUnit: "px", // px | rpx | rem 需要转化的单位 insert: "before", // before | after 需要拷贝的样式插入原样式的位置,默认之前 exclude: [/node_modules/i], // 过滤的文件 disabled: false, // 是否禁用该插件 };
多个媒体查询
const defaultOptions = { mediaQuery: [ { query: "(min-width: 200px)", scale: 2 }, // 超过 200 缩放 { query: "(min-width: 400px)", scale: 0.5 } ], };
小程序pad端自适应
const defaultOptions = { mediaQuery: { query: "(min-width: 750px)", scale: 0.5 }, // 750px以上缩小一倍像素 propList: ["*"], // 应用在所有像素上 transformUnit: "rpx", // 使用在rpx单位 insert: "after", // 小程序媒体查询没有权重,所以要插入原样式之后 };
插件其他效果
对应转化后如果和原本样式一致的话,比如类似
display:block;
或者padding: 0;
,那插件会将对这部分样式舍弃;针对
@keyframes
,如果所有过程都没有转化,则舍弃该@keyframes
,否则保留所有@keyframes
;如果样式原本就包裹在
@media
,则舍弃;
最后
虽然需求项目由于工期,我们还是采用了手写的方法去处理,但是后续的项目我们还是采用了该插件,目前线上效果挺好的~