移动端适配
本文来一起探讨一下移动端有哪些比较好的适配方案。
1.postCSS
在做移动端适配的时候,避免不了这个插件的使用。如果你使用的是
vite
进行构建的话,则直接在根目录创建一个postcss.config.js
即可。
2.方案一:VW
vw方案使用 postcss-px-to-viewport
插件将 px 单位转化为 vw/vh 单位
npm i postcss-px-to-viewport -D
// postcss.config.cjs
module.exports = {
plugins: {
'postcss-px-to-viewport': {
viewportWidth: 375,
},
},
};
别急,你以为就这样完事了吗,并没有。上面只是对设计稿尺寸为 375 的进行转换( vant 设计稿尺寸是 375 🤦♂️),但是我们大部分设计稿尺寸都是 750 ,所以需要额外对 750 尺寸的进行处理。
那么问题来了,怎么配置多个尺寸呢,postcss-px-to-viewport 文档并没有指明,自己尝试解决吧🤷♂️
由于 postcss-px-to-viewport
没有提供类似 postcss-pxtorem
中 rootValue({ file }) {}
的方法,即便使用 module.exports = (param) => {}
这种方式导出postcss
配置,也拿不到当前转换文件的信息,所以无法根据文件路径动态设置 viewportWidth
,
有一种hack方式:通过多次 px2viewport()
处理不同文件来设置viewportWidth
😎
// postcss.config.cjs
const px2viewport = require('postcss-px-to-viewport');
plugins: [
px2viewport({
// vant
viewportWidth: 375,
exclude: [/^(?!.*node_modules\/vant)/],
// include: [/node_modules\/vant/],
}),
px2viewport({
// 非vant
viewportWidth: 750,
exclude: [/node_modules\/vant/],
}),
],
第一个处理 vant 的 px2viewport 为什么不用include选项呢?
因为 postcss-px-to-viewport v1.1.1
不支持 include 配置项,v1.2.0
开始加入include,但是并没有发布到npm仓库🤦♂️
并且由于 postcss-px-to-viewport 不支持 postcss 8.x ,而vite内置postcss 8.x,所以使用postcss-px-to-viewport会抛出警告🤦♂️
改用 postcss-px-to-viewport-8-plugin
替代,既支持 include 配置项,也支持postcss 8.x
我太难了兄弟萌😭
最终完整的postcss.config代码为:
// postcss.config.cjs
const autoprefixer = require('autoprefixer');
const px2viewport = require('postcss-px-to-viewport-8-plugin');
const basePx2viewport = {
unitToConvert: 'px', // 需要转换的单位,默认为 px
// viewportWidth: 750, // 设计稿的视口宽度
unitPrecision: 3, // 单位转换后保留的精度(很多时候无法整除)
propList: [
'*',
// '!font-size'
], // 能转化为vw的属性列表,!font-size表示font-size后面的单位不会被转换
viewportUnit: 'vw', // 指定需要转换成的视口单位,建议使用 vw
fontViewportUnit: 'vw', // 字体使用的视口单位
// 指定不转换为视口单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
// 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位。
// 下面配置表示类名中含有'keep-px'以及'.ignore'类都不会被转换
selectorBlackList: ['.ignore', 'keep-px'],
minPixelValue: 1, // 设置最小的转换数值,这里小于或等于 1px 不转换为视口单位
mediaQuery: false, // 媒体查询里的单位是否需要转换单位
// exclude: [/node_modules/], // 忽略某些文件夹下的文件或特定文件
// include: [/src/], // 如果设置了include,那将只有匹配到的文件才会被转换
};
module.exports = {
plugins: [
autoprefixer(),
// vant
px2viewport({
...basePx2viewport,
viewportWidth: 375,
exclude: [/^(?!.*node_modules\/vant)/],
// include: [/node_modules\/vant/],
}),
// 非vant
px2viewport({
...basePx2viewport,
viewportWidth: 750,
exclude: [/node_modules\/vant/],
}),
],
};
3.方案二:rem方案
rem方案使用 postcss-pxtorem
插件将 px 单位转化为 rem 单位,并且用 lib-flexible
设置rem基准值
尽管连 lib-flexible 自己都建议使用vw方案:
由于viewport单位得到众多浏览器的兼容,lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方案。
但 vw 方案 还是有缺点的。如 vw 方案不适合大屏,因为 vw 是一个比例单位,随着屏幕尺寸变大,使用vw单位的元素、字体也越来越大。但我们肯定是希望在大屏上展示更多的内容,而不是更大的文字、图标。
由于我们的产品使用场景包括手机和平板等设备,所以必须考虑大屏的适配。我曾经尝试过使用 scale
和 zoom
的方式,将大屏上的元素按比例缩小,但是效果都不太理想。最后还是选择 rem方案
,因为 rem方案 可以通过媒体查询来限制基准值(根字体)大小。
配置rem方案就简单多了😅
- 引入 lib-flexible
npm i amfe-flexible
// src/main.ts
import 'amfe-flexible';
- 引入 postcss-pxtorem
npm i postcss-pxtorem -D
// postcss.config.cjs
const autoprefixer = require('autoprefixer');
const pxtorem = require('postcss-pxtorem');
module.exports = {
plugins: [
autoprefixer(),
pxtorem({
rootValue({ file }) {
return file.indexOf('node_modules/vant') !== -1 ? 37.5 : 75;
},
unitPrecision: 5,
propList: ['*'],
selectorBlackList: ['.ignore', 'keep-px'],
minPixelValue: 1,
mediaQuery: false,
}),
],
};
特别注意:
如果用vant官网示例
file.indexOf('vant')
来匹配文件,请==确保你的项目名或文件名==没有包含’vant’
建议改为file.indexOf('node_modules/vant')
一开始写这篇文章时写的demo项目我没注意,用的vant官网示例
file.indexOf('vant')
匹配文件,后来发现怎么转换 rem 单位不对劲,找了半天才发现原来我项目命名为vue3-vant-mobile
,导致 rootValue 一直为 37.5 😓
- 创建
response.less
文件,限制根字体最大值
// src/styles/response.less
// prettier-ignore 忽略prettier对 PX 的自动格式化
// !important 提高权重,使其覆盖 lib-flexible 设置的font-size
@media screen and (min-width: 768px) {
html {
/* prettier-ignore */
font-size: 50PX !important;
}
}
超过了768px就写死字体大小。
这里只是由于插件问题导致vw
方案比rem方案配置起来麻烦许多,本身vw
、rem
方案没有偶孰强孰弱之分,大家看自己需求选择即可✌️