一、rem介绍
1、小程序设置了meta viewport标签,浏览器会结合自身的dpi计算出devicePixelRatio(物理像素分辨率与CSS像素分辨率之比)。
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1">
2、小程序使用的单位为rem,在页面加载的过程中,宿主会根据当前屏幕的分辨率和dpi计算出一个最合适的缩放比例screenRatio。 screenRatio * 100px
将会作为html的font-size的值。
3、在开发的过程中,开发者可根据设计稿的单位进行划算。如: 设计稿上的单位为36px,那么换算的结果36 / 100 rem = 0.36rem
。如果使用了less或者sass那就更方便了。直接写为36 / 100rem
。
document.documentElement.style.fontSize = `${screenRatio * 100}px` ;
二、为什么使用rem
1、首先车机屏幕不等同于普通的手机屏幕,所以不可以完全搬用移动端的适配规则。移动端的适配规则常用的单位有vh、vw、rpx(小程序),但是无论选择哪一种方案,都是基于屏幕宽或者高中的一个尺寸进行缩放。常用到的车机宽高比为 16:9 ~ 3:1之间,但是这个比例范围相对于手机屏幕来说是巨大的,仅对一个方向上进行缩放,会导致另一个方向内容无法控制。例如采用vh进行布局,设计稿给出的尺寸是1800x600
,当把这个小程序放到1280*720
的屏幕上,便会发现。横向的内容常常因为宽度不够大而错位。
2、我们适配的车机屏幕宽度范围在1024px - 2260px,高度在600px - 1080px。这个适配范围根pc端的浏览器很接近,直接使用px便已经满足大部分屏幕的需求。但是考虑还要适配carlife或者特殊的小屏幕。我们还是使用了rem作为适配的单位。在屏幕的宽和高大于1024x600
的情况下。html
的font-size = 100px
,当屏幕的宽高任意一个小于这个值的时候,为了保证屏幕会展示下完整的内容,我们会选取宽高中较小的值,基于最小适配屏幕1024x600
进行缩放。
3、在某些车机上,我们也会进行一些缩放。例如在某些车企1920*1080
的车机上。虽然分别率很大,但其实屏幕的物理尺寸确非常小,原因应该是车企特意修改过dpi或者屏幕的其他参数。所以我们主动让屏幕放大了1.33倍,即html
的font-size = 133px
,这样屏幕的宽度为14.43rem。那么ui也要展示为宽度为1443px下的样式。
三、使用rem的缺点
** rem 不支持媒体查询。**
如以下写法不支持, 媒体查询的时候,浏览器默认1rem = 16px。所以在开发的过程中,我们都是通过js获取具体的值,然后给dom设置class类名。
@media screen and (min-width: 1.72rem) {
.main-content {
margin:0 5.1282051282%
}
}
@media screen and (min-width: 2.28rem) {
.main-content {
margin:0 5.1282051282%
}
}
四、获取缩放系数
screenRatio系数可以通过swan.iovauto.getIovConfig拿到。
swan.iovauto.getIovConfig({
success: res => {
console.log(res.screenRatio);
console.log(res.dpi);
},
fail: err => {
this.setMode();
}
});
在开发的过程中,因为当前环境不是车机,所以html不会设置fontSize属性,但为了开发过程中正常使用rem,请在css中主动设置html的fontSize属性,默认值为100px。
// app.less
html {
font-size: 100px;
}
五、单容器和双容器的切换
1、在开发的过程当中,经常会遇到,当屏幕的宽度足够大时。页面可以分两列展示内容,但是随着页面宽度的减小,双容器可能无法满足要求,因此需要把双容器变为单容器。如下图所示:
2、假如ui提出的规范是,当页面的宽度小于1376px时,页面将变为单容器展示。因为我们是采用的rem作为单位,那么怎么判断当前宽度是多少像素呢?
// 首先拿到当前容器的screenRatio
const minWidth = 1720;
swan.iovauto.getIovConfig({
success: res => {
console.log(res);
const screenRatio = res.screenRatio;
// 拿到当前容器的宽度(px);
const res = swan.getSystemInfoSync();
// 右侧异形屏区域
const screenArcRight = parseFloat(res.screenArcRight || 0, 10);
// 左侧异形屏区域
const screenArcLeft = parseFloat(res.screenArcLeft || 0, 10);
const width = res.windowWidth - screenArcRight - screenArcLeft;
// 判断当前容器的逻辑宽度。
const dp = width / screenRatio;
if (dp > minWidth) {
console.log('当前为双容器');
} else {
console.log('当前为单容器');
}
},
fail: err => {
this.setMode();
}
});