前言
關(guān)于手機(jī)屏幕響應(yīng)式編程,從大約從iphone 6時(shí)代就開始討論了,之后的方案是一年一個(gè),如今,都2019年了,也該有個(gè)結(jié)論了。
以往曾經(jīng)流行過(guò)em方案,后來(lái)是rem方案,后來(lái)又有vw方案,到最近兩年,由于腳手架的逐步進(jìn)化,加上vue等框架的流行,尺寸現(xiàn)在都流行動(dòng)態(tài)計(jì)算,也就是說(shuō):
將屏幕寬度假想為750個(gè)單位,單位可以叫“rpx”(微信小程序),uni-app里叫“upx”,不過(guò)也不要以為uni-app的upx只是給rpx改了改名,畢竟在H5端和APP都是生效的。如果看uni-app生成的H5,會(huì)發(fā)現(xiàn),尺寸單位依然是px,顯然,所有px值都是由js計(jì)算出來(lái)的(并不是腳手架生成的靜態(tài)值)。
這就好玩了,這種方式打臉了一些使用vw、rem的技術(shù)方案,因?yàn)槲揖蚿x一萬(wàn)年,依然做得到響應(yīng)式、自適應(yīng),但是它的技術(shù)細(xì)節(jié)就不太容易弄清。
而今天我講的viewport元數(shù)據(jù)方案,是最簡(jiǎn)單,但又沒(méi)什么明顯缺陷的方案。當(dāng)然,比起uni-app還是差一點(diǎn),畢竟技術(shù)擺在那。
我個(gè)人做法是優(yōu)先用uni-app,簡(jiǎn)單的H5就用viewport方案,能應(yīng)付百分之九十九的場(chǎng)景。
viewport元數(shù)據(jù)方案科普
提起viewport元數(shù)據(jù),最典型的元數(shù)據(jù)規(guī)則是:
<meta name="viewport" content="
width=device-width,
initial-scale=1.0,
minimum-scale=1.0,
maximum-scale=1.0,
user-scalable=no
">
實(shí)際書寫的時(shí)候應(yīng)該寫成1行,我這里為了方便閱讀給做了換行。
這幾句是什么意思?可以看我寫的《通俗講解CSS pixels、device pixels、device-width、layout viewport、visual viewport、ideal viewport六個(gè)概念》。
好,現(xiàn)在假定你閱讀了上文。說(shuō)白了,device-width就是設(shè)備邏輯像素寬度,在最早期就等于320,后面手機(jī)越出越多,device-width可能等于360、375、414等等,手機(jī)出廠之前就定好了。
viewport元數(shù)據(jù)方案內(nèi)容
以360px邏輯分辨率作為頁(yè)面寬度標(biāo)準(zhǔn),以16px作為標(biāo)準(zhǔn)字體尺寸。
設(shè)計(jì)師的畫布可以為720px,也可以為750px,也可以為1080px,都成,越大則手機(jī)顯示的畫面越細(xì)膩。
除字體之外的尺寸,都根據(jù)360px的畫布來(lái)定px值,比如一個(gè)正文頁(yè)面,正文的留白就可以是12px。完全不用考慮什么rem之類的尺寸單位。
字體的尺寸,上面說(shuō)了,標(biāo)準(zhǔn)就是16px,想要小字體就寫14px、12px、10px,想要大字體就寫18px等等。也完全不用考慮rem之類的尺寸單位。
-
加一些代碼:
a. 在<head>最頂部寫上一個(gè)沒(méi)有content的元數(shù)據(jù):<meta name="viewport" id="viewport">b. 緊貼上文代碼,寫上:
<script> var initialscale = document.documentElement.clientWidth / 360; document.getElementById('viewport').content = "width=360, initial-scale=" + initialScale + ", maximum-scale=" + initialScale + ", minimum-scale=" + initialScale + ", user-scalable=no" </script>
viewport元數(shù)據(jù)方案原理
viewport元數(shù)據(jù)的牛逼之處就在于縮放。
首先說(shuō)為什么用360px作為標(biāo)準(zhǔn),因?yàn)?60px接近真實(shí)的手機(jī)寬度,你在電腦上用QQ截圖工具量出一個(gè)360px長(zhǎng)度(別用視網(wǎng)膜屏幕量,這不準(zhǔn)),然后你把自己手機(jī)貼近電腦屏幕,你會(huì)發(fā)現(xiàn)360px長(zhǎng)度跟手機(jī)寬度差不多。
然后,還有一點(diǎn),就是360px寬度下,用16px作為標(biāo)準(zhǔn)字體,是符合人眼的最舒適感的。如果你要用375px作為標(biāo)準(zhǔn)寬度,那么16px的字就顯得比較小,不適合閱讀了。當(dāng)然了,這就純看你的想法了,因?yàn)?60px配16px字最佳這句話是我說(shuō)的,不是公認(rèn)的,你也可以認(rèn)為375px配16px字最佳,這就是人眼的感受不同了,就好比有些人喜歡看小字,有些人喜歡看大字,這就不是程序上的“1+1=2”那么死板了。
viewport元數(shù)據(jù)的作用就是,先把width強(qiáng)行設(shè)為360。這時(shí)候,很多安卓手機(jī)本身就是360邏輯像素,所以還好,但是iPhone最新的手機(jī)都是414邏輯像素,這時(shí)候,如果不做其他設(shè)置,那么iPhone手機(jī)上顯示的字都是偏小的。然后再給initial-scale、maximum-scale、minimum-scale設(shè)一個(gè)比例尺,這個(gè)比例尺就是動(dòng)態(tài)計(jì)算出來(lái)的,比如iPhone 6的比例尺就是375 / 360 = 1.04167,這樣,瀏覽器會(huì)把整個(gè)頁(yè)面再放大1.04167倍,就實(shí)現(xiàn)了各個(gè)手機(jī)一致的顯示效果。
也就是說(shuō),屏幕一行永遠(yuǎn)是顯示360 / 16 = 22.5個(gè)字,無(wú)論你手機(jī)多小,還是多大,都是這樣的一行22.5個(gè)字。而圖片呢?比如一張圖設(shè)了180px寬,那么在小手機(jī)是占左半屏那么寬,在大手機(jī)上也是占左半屏那么寬。
這樣就實(shí)現(xiàn)了響應(yīng)式。
這種方式的實(shí)現(xiàn),源自于瀏覽器級(jí)別的渲染原理,也是最準(zhǔn)確的渲染,是最嚴(yán)格意義的放大縮小。
案例
瀏覽器打開http://common.hebei.sina.com.cn/app/2019/ajsc2019/,然后F12,切換手機(jī)模式,先看iPhone 5模式,刷新頁(yè)面,整個(gè)頁(yè)面是比較小的,元數(shù)據(jù)是這樣:

然后切換到iPhone 6,刷新頁(yè)面,頁(yè)面整體變大,元數(shù)據(jù)是這樣:

那么,是不是尺寸值都是用的px呢?select一個(gè)首頁(yè)的圖片看看:

可以看到,就是px值,而且是基于360px畫布寫出來(lái)的px值。
發(fā)絲線
這個(gè)方案不可解決發(fā)絲線寬度的問(wèn)題,想解決發(fā)絲線寬度,還是要用發(fā)絲線本身的解決方案。
方案缺陷
不支持viewport的手機(jī)瀏覽器,就不能采用這種方案了,比如安卓古老版本的自帶瀏覽器。但是,2019年了,還有這種手機(jī)么?這種手機(jī)的使用者又能給你帶來(lái)多少價(jià)值呢?
-
設(shè)計(jì)稿中的px值都要經(jīng)過(guò)換算才能用。怎么辦?有2種辦法:
設(shè)計(jì)規(guī)范里面的固定尺寸,和常用尺寸,就直接腦子記住,比如留白,設(shè)計(jì)稿里是20px,那么我們css里就寫10px就可以了,盡管嚴(yán)格說(shuō)應(yīng)該寫20 * 360 / 750 = 9.6px,但是也沒(méi)必要那么精確了,10px并不是不可以,只要你堅(jiān)持用10px就行。
不在設(shè)計(jì)規(guī)范里的尺寸,要么就簡(jiǎn)單的口算除以2,想要精確值就可以使用sass計(jì)算,我們先定義一個(gè)mixin和一個(gè)function,mixin用于多個(gè)值,fuction用于單個(gè)值,各有各的場(chǎng)合:
@mixin scaler($property, $values...) { $resultValues: ''; @each $value in $values { $resultValues: #{$resultValues + $value * 36 / 75 + "px "}; } #{$property}: $resultValues; } @function scaler($value) { @return #{$value * 36 / 75 + 'px'}; }其中36和75根據(jù)你的實(shí)際情況改。
使用:
body { @include scaler(margin, 2, 4, 6, 8); padding: scaler(5) scaler(10); }結(jié)果:
image.png其他css預(yù)處理器也同樣道理。
從這個(gè)角度說(shuō),拿375px作為標(biāo)準(zhǔn)寬度似乎更便于開發(fā),所以尺寸都除以2就好了??偠灾S你定。
最后一個(gè)問(wèn)題,為什么標(biāo)準(zhǔn)寬度不直接用750px?
標(biāo)準(zhǔn)寬度用750px也是可以的,這樣的話,尺寸就可以完全照抄設(shè)計(jì)稿(如果設(shè)計(jì)稿是750px的話)。這時(shí)候就是字體尺寸怎么寫的問(wèn)題了。
假設(shè)我真讓標(biāo)準(zhǔn)寬度使用750px,那么字體的標(biāo)準(zhǔn)尺寸就應(yīng)該是16 * 750 / 360 = 33.33px,約等于34px,作為標(biāo)準(zhǔn)字體尺寸,記下這個(gè)尺寸?;蛘吣憔陀?2px作為標(biāo)準(zhǔn)尺寸也是可以的,還是那句話,你們開發(fā)者和你們收到的反饋說(shuō)多少px看著舒服,就用多少px。
比34px字體小一點(diǎn)的字體就可以是32px、30px,依然2個(gè)2個(gè)的遞減。
這時(shí)候還有一個(gè)問(wèn)題就是兼容PC端的問(wèn)題。
上面的例子有一個(gè) http://common.hebei.sina.com.cn/app/2019/ajsc2019/,它是兼容PC端的,在PC端上viewport失效,像素都是PC真實(shí)像素,這時(shí)候,如果標(biāo)準(zhǔn)寬度是360px,那么它在PC端依然顯示360px,跟真實(shí)手機(jī)的大小是接近的,只要經(jīng)過(guò)簡(jiǎn)單樣式兼容,就可以兼容PC端。而如果是以750px為標(biāo)準(zhǔn),那么就會(huì)在PC端顯示一個(gè)750px寬度的網(wǎng)頁(yè),顯然,這是一種傻大傻大的網(wǎng)頁(yè),體驗(yàn)會(huì)非常差。
所以結(jié)論是,如果你打算兼容PC端,那么標(biāo)準(zhǔn)寬度設(shè)為360還是375都可以,但不能是750px,如果從來(lái)不需要兼容PC端,那么標(biāo)準(zhǔn)寬度設(shè)750px完全可以,畢竟跟設(shè)計(jì)稿尺寸完全一致,不需要換算,是一個(gè)優(yōu)勢(shì)。
假設(shè)你決定了用750px作為標(biāo)準(zhǔn)寬度,那么,下面這段代碼依舊必須寫,只不過(guò)360要改成750而已。
<script>
var initialscale = document.documentElement.clientWidth / 750;
document.getElementById('viewport').content = "width=750, initial-scale=" + initialScale + ", maximum-scale=" + initialScale + ", minimum-scale=" + initialScale + ", user-scalable=no"
</script>
那么uni-app做的H5兼容PC端么?
默認(rèn)不兼容,需手動(dòng)改造可以實(shí)現(xiàn)兼容。
如果所有的組件都是以u(píng)px為單位開發(fā),那么只需要限定body寬度為375px,同時(shí)為了把fixed元素約束在375px內(nèi),需要給body加上transform: translateZ(0)(原理見(jiàn)如何讓position: fixed不再基于瀏覽器窗口定位?)。
如果有些尺寸使用了upx之外的單位,那就麻煩大了,兼容性比較難調(diào),有一個(gè)辦法是做一個(gè)居中的、375px寬、瀏覽器那么高的iframe,嵌套你的H5,也可以實(shí)現(xiàn)PC端兼容。
vw、rem方案兼容PC端么?
至少市面上的方案默認(rèn)不去考慮PC端,也就是說(shuō)PC打開頁(yè)面也是瀏覽器全寬,頁(yè)面傻大到爆炸。
所以如果要兼容也需要另外考慮,就不多說(shuō)了。
