《微信小程序七日谈》系列文章:javascript
本系列的文章并不是初学教程,而是笔者在具体开发过程当中遇到的问题以及部分解决方案。css
上篇文章第一天:人生若只如初见简单记录了笔者初步上手开发微信小程序遇到的一些问题,其中提到了wxss的部分细节问题。这篇文章以笔者在开发小程序响应式UI当中遇到的一些问题为例,简单记录一下使用wxss为响应式开发带来的一些模式和思惟上的改变。html
前端工程师对rem
很是熟悉,rem是以html元素的font-size
为基准的尺寸计量单位。rem方便了开发者对响应式UI的尺寸进行统筹管理。前端
wxss中的rem
与css中的rem
的含义彻底不一样,下面是微信官方文档中对rem的定义:java
rem(root em): 规定屏幕宽度为20rem;1rem = (750/20)rpxcss3
其中的750这个数值是wxss将设备屏幕的宽统必定义为750rpx,对此,下文会讲解。bootstrap
各位读到这里是否脑海里浮现了一个想法:wxss的rem怎么听起来有点像bootstrap的栅格系统呢?小程序
wxss将屏幕宽分为20rem,bootstrap将设备屏幕宽度分为12列。初看起来确实有点相似。但其实wxss的rem和bootstrap的栅格系统并不相同。虽然wxss和bootstrap都是讲屏幕尺寸分割为单元格,但rem和栅格的定位不一样。微信小程序
bootstrap的开发者使用指定的classname进行元素间的比例分配,这其实接近为css3中的flexbox;而wxss的rem是一个尺寸单位,你能够在合理的场景下将任何以px
为单位的属性值替换为rem
。微信
因此,开发小程序UI时,须要抛弃思惟中对rem的常规认知。截止目前,笔者还未遇到必须使用小程序rem的需求,但愿你们踊跃探讨。
上文提到wxss将设备屏幕的宽统必定义为750rpx,其中的rpx是wxss带来的新的尺寸单位。rpx的定义以下:
rpx(responsive pixel): 能够根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
css中的px与设备的物理像素并不是绝对的一比一关系。尤为是在移动设备上,px与物理像素的比例与设备的dpr(devicePixelRadio)有关,详细的对应关系各位可自行查阅。
rpx称为相对像素值,rpx与物理像素也并不是绝对的一比一关系。wxss将设备宽定义为750rpx,是以iPhone6的分辨率(750x1334)为基准划分的。也就是说,在iPhone6上,1rpx=1物理像素=0.5px。官方文档列出了几种屏幕的rpx对应关系以下:
你们能够从中获得rpx和px的换算公式:
1rpx = 1px/dpr
其中iPhone6的dpr=2。
那么rpx带给响应式UI什么改变呢?
目前大部分UI工程师在制做UI稿的时候是按照iPhone6的尺寸设计,而后前端工程师按照UI稿尺寸的一半进行UI的还原开发。这样在iPhone6以及接近iPhone6尺寸的设备上是没有任何问题的。可是移动设备的尺寸多种多样,咱们的产品不可能只应对iPhone6(何况iPhone7已经来了哈哈...),因此一般的作法是使用css的媒体查询根据设备的尺寸再进行适配微调。
若是使用rpx是否是就能够解决这个问题呢?笔者在开发过程当中尝试使用rpx代替px,使用UI稿的原始尺寸还原UI,截止到目前体验很是好。rpx自己表明的是相对像素,因此不论多大尺寸的屏幕,rpx的UI占据的屏幕比例是绝对固定的,是等比缩放的。
可是rpx并不是万能的,好比使用css sprites的图标。请看下文。
使用css sprites做为图标背景时,每一个图标的尺寸是以px为单位固定的,好比:
.icon{ background-image: url('//image.daojia.com/icon.png'); display: inline-block; vertical-align: middle; } .icon__circle{ background-position: 0 0; width: 40px; height: 40px; }
若是图标的尺寸不符合UI设计,则进行必定比例的缩放:
.icon__circle{ transform: scale(0.5); }
也就是说,使用sprites图标不可避免地会用到px,若是与rpx结合使用,是不能保证同rpx同样等比缩放效果的。那么怎么去解决这个问题呢?
根据上文总结出的rpx与px的换算公式,若是想要将以px规定的UI达到同rpx同样的响应式缩放效果,必须将px与设备的dpr进行计算。可是css做为一种标记语言,并不具有动态特性,没法动态地获取设备dpr并计算。因此,单纯使用wxss并不能解决上文提到的问题。
好消息是小程序提供了获取设备信息的API,而且支持CommonJS模块化方案。有了这些功能,咱们能够在封装组件时加入动态的逻辑配置。
仍是以上文的代码为例,sprites图的icon__circle
尺寸为40px*40px,咱们的目标是将其适配为20rpx,如下是笔者的开发方案。
好比项目中有一个user组件,包含了一些sprites图标节点。user组件的文件目录以下:
user.wxml
- 组件模板;user.wxss
- 组件样式;user.js
- 组件逻辑。首先给user.wxml
中icon对应的element设置动态的transform
:
<view class='icon icon__circle' style="transform: scale({{iconScale}})"></view>
其中iconScale
是引用user的外部组件index传递给user组件的:
<import src='user.wxml'/> <template is='product-user' data="{{iconScale: userIconScale}}"/>
userIconScale是index组件的一个data,userIconScale的值并不是index组件规定的,而是由index组件的js调用user.js
动态获取的。如下代码是user.js
暴露的API:
const ORIGIN_ICON_PX = 40; const TARGET_ICON_RPX = 20; module.exports = { getIconScale() { let result = 1; wx.getSystemInfo({ success: function(res) { let _dpr = res.pixelRatio; result = TARGET_ICON_RPX/(ORIGIN_ICON_PX * _dpr); } }); return result; } }
而后在index组件的js中调用以上API:
let getIconScale = require('user.js').getIconScale; Page({ data: { userIconScale: 1 }, onLoad(){ this.setData({ userIconScale: getIconScale() }); } });
以上只是初步的方案,不少地方须要再仔细琢磨。不过以上方案基本上具有了一个组件的逻辑封装,而且达到了咱们对响应式的开发需求。
次日的开发经历仍是很有收获的,不只仅是对小程序开发模式的熟悉,并且对一些综合方案也有必定的深刻。期待后续吧。