《微信小程序七日談》系列文章: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() }); } });
以上只是初步的方案,不少地方須要再仔細琢磨。不過以上方案基本上具有了一個組件的邏輯封裝,而且達到了咱們對響應式的開發需求。
次日的開發經歷仍是很有收穫的,不只僅是對小程序開發模式的熟悉,並且對一些綜合方案也有必定的深刻。期待後續吧。