移动端设备的尺寸很多,而UI设计稿一般只会基于一个尺寸(一般是750px)进行设计。假如开发人员完全基于该设计稿进行开发,就会出现一种现象,在不同尺寸的设备上,页面的展示效果各不相同,甚至可能出现布局错乱或者出现横向滚动条等情况。因此,开发人员就需要考虑如何让页面内容能够自适应设备尺寸,在设备尺寸较大时内容大一些,设备尺寸小的时候内容也能缩小,让页面在不同的设备尺寸下尽量呈现一致的展示效果。
目前流行的移动端适配方案有两种,rem和viewport,由于viewport单位得到众多浏览器的兼容,现在更多的人推荐使用viewport方案来解决移动端适配问题。下面将对这两个方案做一个大致的介绍。
rem是一个相对于页面根元素html的font-size的一个单位,举个例子,假如设置了根元素html的font-size为18px,那么,1rem 等于 18px。由此可知,rem的大小是会随着根元素html的font-size的改变而改变的。rem方案就是利用了这一点,根据不同的屏幕尺寸,来设置不同的根元素html的font-size的大小,以此来达到适配不同屏幕尺寸的目的。
我们可以使用手淘的amfe-flexible插件,该插件会根据不同设备的屏幕宽度来设置font-size值,下面来简单看一下其实现原理。以下代码是该插件源码的一部分,可以看到,它先是获取了设备宽度,然后除以10。这里大概意思是,将设备宽度分为10等份,然后将一等份的大小作为html元素的font-size值,也就是说1rem就会等于设备的1等份大小(前面说了1rem等于html元素的font-size值)。
// ...
function setRemUnit () {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
// ...
现在举个例子,750px设计稿下,divA的宽度为50px,在具体开发中,divA的宽度应该是多少rem呢?在写divA的宽度时,我们需要自行进行计算,将其rem值设为x,代入该式子x:50=1:75
,得出x≈0.67rem,所以,我们这样设置divA的宽度:
.divA {
width: 0.67rem;
}
可以看出,将设计稿上的px值转换为rem的过程其实是比较繁琐的,接下来介绍下一个能够自动将px转为rem的插件。
postcss-pxtorem是一个能将px转换为rem的工具,这样我们在开发过程中只需要参照设计稿,使用px单位进行开发,由该工具帮我们转换成rem单位即可。只需要在postcss.config.js中进行如下配置:
module.exports = {
"plugins": {
"postcss-pxtorem": {
rootValue: 75, // 根据设计图尺寸写,设计图是750,就写75
propList: ['*'] // 需要被转换的属性
}
}
}
如果是使用vant作为移动端开发的组件库,那么就需要注意,vant是基于375写的,而我们开发的设计稿大多750px。所以rootValue设置为75的话,vant的样式就小了一半。通过查阅postcss-pxtorem官网可以知道,rootValue的值可以是number/function,当它是函数的时候,postcss-pxtorem处理每个css文件的时候都会来调用这个函数,且被处理的css文件的相关信息会通过参数形式传递给该函数。因此,我们可以判断是vant文件的样式,还是我们的样式,来决定rootValue的大小。
改写postcss.config.js文件:
module.exports = {
"plugins": {
"postcss-pxtorem": {
rootValue({ file }) {
return file.indexOf('vant') !== -1 ? 37.5 : 75;
},
propList: ['*'] // 需要被转换的属性
}
}
}
通常viewport是指视窗、视口,即浏览器用来显示网页的那部分区域。在移动端开发中,我们希望页面宽度和设备宽度一致,并把这个viewport称为ideal viewport(理想视口)。我们设置public/index.html添加viewport元数据标签,就是为了得到一个ideal viewport。
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
viewport方案即是使用vw/vh作为样式单位。vw、vh将viewport分成了一百等份,1vw等于视口1%的宽度,1vh等于视口1%的高度。当我们的设计稿是750px时,1vw就等于7.5px。还是用之前那个例子,750px设计稿下,divA的宽度为50px,使用vw作为样式单位,divA的宽度是多少vw呢?还是将divA的宽度设置x vw,代入x:50 = 1:7.5
,得到x≈6.67vw。
可以感受到,自行计算的过程相当影响开发进度。所以我们引入了postcss-px-to-viewport插件。
postcss-px-to-viewport是一个将px单位转换为视口单位(一般就是vw)的 PostCSS 插件。这样我们在开发过程中只需要参照设计稿,使用px单位进行开发,由该工具帮我们转换成vw单位即可。只需要在postcss.config.js中进行如下配置,同样地,使用vant组件库的情况下,需要做兼容处理。
module.exports = ({ file }) => {
const vwUnit = file && file.indexOf('vant') !== -1 ? 375 : 750;
return {
plugins: {
'postcss-px-to-viewport': {
viewportWidth: vwUnit, // 设计稿的宽度
unitPrecision: 5, // 转换后的位数,即小数点位数
viewportUnit: 'vw', // 转换成的视窗单位
propList: ['*'], // 要进行转换的属性,如果某个属性不进行转换,只需在其前加个“!”即可
selectorBlackList: [], // 不进行转换的选择器
minPixelValue: 1, // 小于或等于1px则不进行转换
mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
},
},
};
};
npm install amfe-flexible --save
npm install postcss-pxtorem --save-dev
import 'amfe-flexible';
module.exports = {
"plugins": {
"postcss-pxtorem": {
rootValue({ file }) {
return file.indexOf('vant') !== -1 ? 37.5 : 75;
},
propList: ['*'] // 需要被转换的属性
}
}
}
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
npm install postcss-px-to-viewport --save-dev
module.exports = ({ file }) => {
const vwUnit = file && file.indexOf('vant') !== -1 ? 375 : 750;
return {
plugins: {
'postcss-px-to-viewport': {
viewportWidth: vwUnit, // 设计稿的宽度
unitPrecision: 5, // 转换后的位数,即小数点位数
viewportUnit: 'vw', // 转换成的视窗单位
propList: ['*'], // 要进行转换的属性,如果某个属性不进行转换,只需在其前加个“!”即可
selectorBlackList: [], // 不进行转换的选择器
minPixelValue: 1, // 小于或等于1px则不进行转换
mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
},
},
};
};