那么趁此Amfe阿里無線前端團(tuán)隊雙11技術(shù)連載之際,用一個實戰(zhàn)案例來告訴大家,手淘的H5頁面是如何實現(xiàn)多終端適配的,希望這篇文章對大家在Mobile的世界中能過得更輕松。 目標(biāo)拿一個雙11的Mobile頁面來做案例,比如你實現(xiàn)一個類似下圖的一個H5頁面: 目標(biāo)很清晰,就是做一個這樣的H5頁面。 痛點雖然H5的頁面與PC的Web頁面相比簡單了不少,但讓我們頭痛的事情是要想盡辦法讓頁面能適配眾多不同的終端設(shè)備??纯聪聢D你就會知道,這是多么痛苦的一件事情: 點擊這里查看更多終端設(shè)備的參數(shù)。 再來看看手淘H5要適配的終端設(shè)備數(shù)據(jù): 看到這些數(shù)據(jù),是否死的心都有了,或者說為此捏了一把汗出來。 手淘團(tuán)隊適配協(xié)作模式早期移動端開發(fā),對于終端設(shè)備適配問題只屬于Android系列,只不過很多設(shè)計師常常忽略Android適配問題,只出一套iOS平臺設(shè)計稿。但隨著iPhone6,iPhone6+的出現(xiàn),從此終端適配問題不再是Android系列了,也從這個時候讓移動端適配全面進(jìn)入到“雜屏”時代。 為了應(yīng)對這多么的終端設(shè)備,設(shè)計師和前端開發(fā)之間又應(yīng)該采用什么協(xié)作模式?或許大家對此也非常感興趣。 而整個手淘設(shè)計師和前端開發(fā)的適配協(xié)作基本思路是:
還是上一張圖吧,因為一圖勝過千言萬語: 在此也不做更多的闡述。在手淘的設(shè)計師和前端開發(fā)協(xié)作過程中:手淘設(shè)計師常選擇iPhone6作為基準(zhǔn)設(shè)計尺寸,交付給前端的設(shè)計尺寸是按 根據(jù)上面所說的,設(shè)計師給我們的設(shè)計圖是一個 前端開發(fā)完成終端適配方案拿到設(shè)計師給的設(shè)計圖之后,剩下的事情是前端開發(fā)人員的事了。而手淘經(jīng)過多年的摸索和實戰(zhàn),總結(jié)了一套移動端適配的方案——flexible方案。 這種方案具體在實際開發(fā)中如何使用,暫時先賣個關(guān)子,在繼續(xù)詳細(xì)的開發(fā)實施之前,我們要先了解一些基本概念。 一些基本概念在進(jìn)行具體實戰(zhàn)之前,首先得了解下面這些基本概念(術(shù)語): 視窗 viewport簡單的理解,viewport是嚴(yán)格等于瀏覽器的窗口。在桌面瀏覽器中,viewport就是瀏覽器窗口的寬度高度。但在移動端設(shè)備上就有點復(fù)雜。 移動端的viewport太窄,為了能更好為CSS布局服務(wù),所以提供了兩個viewport:虛擬的viewportvisualviewport和布局的viewportlayoutviewport。 George Cummins在Stack Overflow上對這兩個基本概念做了詳細(xì)的解釋。 而事實上viewport是一個很復(fù)雜的知識點,上面的簡單描述可能無法幫助你更好的理解viewport,而你又想對此做更深的了解,可以閱讀PPK寫的相關(guān)教程。 物理像素(physical pixel)物理像素又被稱為設(shè)備像素,他是顯示設(shè)備中一個最微小的物理部件。每個像素可以根據(jù)操作系統(tǒng)設(shè)置自己的顏色和亮度。正是這些設(shè)備像素的微小距離欺騙了我們?nèi)庋劭吹降膱D像效果。 設(shè)備獨立像素(density-independent pixel)設(shè)備獨立像素也稱為密度無關(guān)像素,可以認(rèn)為是計算機(jī)坐標(biāo)系統(tǒng)中的一個點,這個點代表一個可以由程序使用的虛擬像素(比如說CSS像素),然后由相關(guān)系統(tǒng)轉(zhuǎn)換為物理像素。 CSS像素CSS像素是一個抽像的單位,主要使用在瀏覽器上,用來精確度量Web頁面上的內(nèi)容。一般情況之下,CSS像素稱為與設(shè)備無關(guān)的像素(device-independent pixel),簡稱DIPs。 屏幕密度屏幕密度是指一個設(shè)備表面上存在的像素數(shù)量,它通常以每英寸有多少像素來計算(PPI)。 設(shè)備像素比(device pixel ratio)設(shè)備像素比簡稱為dpr,其定義了物理像素和設(shè)備獨立像素的對應(yīng)關(guān)系。它的值可以按下面的公式計算得到:
在JavaScript中,可以通過 dip或dp,(device independent pixels,設(shè)備獨立像素)與屏幕密度有關(guān)。dip可以用來輔助區(qū)分視網(wǎng)膜設(shè)備還是非視網(wǎng)膜設(shè)備。 縮合上述的幾個概念,用一張圖來解釋: 眾所周知,iPhone6的設(shè)備寬度和高度為 如下圖所示,某元素的CSS樣式: CSS
在不同的屏幕上,CSS像素所呈現(xiàn)的物理尺寸是一致的,而不同的是CSS像素所對應(yīng)的物理像素具數(shù)是不一致的。在普通屏幕下 有關(guān)于更多的介紹可以點擊這里詳細(xì)了解。 看到這里,你能感覺到,在移動端時代屏幕適配除了Layout之外,還要考慮到圖片的適配,因為其直接影響到頁面顯示質(zhì)量,對于如何實現(xiàn)圖片適配,再此不做過多詳細(xì)闡述。這里盜用了@南宮瑞揚(yáng)根據(jù)mir.翻譯的一張信息圖: meta標(biāo)簽
XHTML
代碼以顯示網(wǎng)頁的屏幕寬度定義了視窗寬度。網(wǎng)頁的比例和最大比例被設(shè)置為100%。 留個懸念,因為后面的解決方案中需要重度依賴 CSS單位rem在W3C規(guī)范中是這樣描述
簡單的理解, 前端實現(xiàn)方案了解了前面一些相關(guān)概念之后,接下來我們來看實際解決方案。在整個手淘團(tuán)隊,我們有一個名叫 lib-flexible是什么?
當(dāng)然你可以直接使用阿里CDN: JavaScript
將代碼中的 使用方法
第一種方法是將文件下載到你的項目中,然后通過相對路徑添加: XHTML
或者直接加載阿里CDN的文件: XHTML
另外強(qiáng)烈建議對JS做內(nèi)斂處理,在所有資源加載之前執(zhí)行這個JS。執(zhí)行這個JS后,會在 如此一來,頁面中的元素,都可以通過 除此之外,在引入 XHTML
其中 JavaScript
flexible的實質(zhì)
JavaScript
事實上他做了這幾樣事情:
案例實戰(zhàn)了解Flexible相關(guān)的知識之后,咱們回到文章開頭。我們的目標(biāo)是制作一個適配各終端的H5頁面。別的不多說,動手才能豐衣足食。 創(chuàng)建HTML模板
XHTML
正如前面所介紹的一樣,首先加載了Flexible所需的配置: XHTML
這個時候可以根據(jù)設(shè)計的圖需求,在HTML文檔的 XHTML
這僅是一個示例文檔,大家可以根據(jù)自己風(fēng)格寫模板。 為了能更好的測試頁面,給其配置一點假數(shù)據(jù): JavaScript
接下來的工作就是美化工作了。在寫具體樣式之前,有幾個點需要先了解一下。 把視覺稿中的
|
1 2 |
1a = 7.5px 1rem = 75px |
那么我們這個示例的稿子就分成了10a
,也就是整個寬度為10rem
,<html>
對應(yīng)的font-size
為75px
:
這樣一來,對于視覺稿上的元素尺寸換算,只需要原始的px值
除以rem基準(zhǔn)值
即可。例如此例視覺稿中的圖片,其尺寸是176px * 176px
,轉(zhuǎn)換成為2.346667rem * 2.346667rem
。
在實際生產(chǎn)當(dāng)中,如果每一次計算px
轉(zhuǎn)換rem
,或許會覺得非常麻煩,或許直接影響大家平時的開發(fā)效率。為了能讓大家更快進(jìn)行轉(zhuǎn)換,我們團(tuán)隊內(nèi)的同學(xué)各施所長,為px
轉(zhuǎn)換rem
寫了各式各樣的小工具。
CSSREM是一個CSS的px
值轉(zhuǎn)rem
值的Sublime Text3自動完成插件。這個插件是由@正霖編寫。先來看看插件的效果:
有關(guān)于CSSREM如何安裝、配置教程可以點擊這里查閱。
除了使用編輯器的插件之外,還可以使用CSS的處理器來幫助大家處理。比如說Sass、LESS以及PostCSS這樣的處理器。我們簡單來看兩個示例。
使用Sass的同學(xué),可以使用Sass的函數(shù)、混合宏這些功能來實現(xiàn):
1 2 3 4 5 6 7 8 9 |
@function px2em($px, $base-font-size: 16px) { <a href='http://www./members/jinyi7016'>@if</a> (unitless($px)) { @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you"; @return px2em($px + 0px); // That may fail. } @else if (unit($px) == em) { @return $px; } @return ($px / $base-font-size) * 1em; } |
除了使用Sass函數(shù)外,還可以使用Sass的混合宏:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@mixin px2rem($property,$px-values,$baseline-px:16px,$support-for-ie:false){ //Conver the baseline into rems $baseline-rem: $baseline-px / 1rem * 1; //Print the first line in pixel values <a href='http://www./members/jinyi7016'>@if</a> $support-for-ie { #{$property}: $px-values; } //if there is only one (numeric) value, return the property/value line for it. <a href='http://www./members/jinyi7016'>@if</a> type-of($px-values) == "number"{ #{$property}: $px-values / $baseline-rem; } @else { //Create an empty list that we can dump values into $rem-values:(); @each $value in $px-values{ // If the value is zero or not a number, return it <a href='http://www./members/jinyi7016'>@if</a> $value == 0 or type-of($value) != "number"{ $rem-values: append($rem-values, $value / $baseline-rem); } } // Return the property and its list of converted values #{$property}: $rem-values; } } |
有關(guān)于更多的介紹,可以點擊這里進(jìn)行了解。
除了Sass這樣的CSS處理器這外,我們團(tuán)隊的@頌奇同學(xué)還開發(fā)了一款npm
的工具px2rem。安裝好px2rem之后,可以在項目中直接使用。也可以使用PostCSS。使用PostCSS插件postcss-px2rem:
1 2 3 4 5 6 7 8 9 10 |
var gulp = require('gulp'); var postcss = require('gulp-postcss'); var px2rem = require('postcss-px2rem'); gulp.task('default', function() { var processors = [px2rem({remUnit: 75})]; return gulp.src('./src/*.css') .pipe(postcss(processors)) .pipe(gulp.dest('./dest')); }); |
除了在Gulp中配置外,還可以使用其他的配置方式,詳細(xì)的介紹可以點擊這里進(jìn)行了解。
配置完成之后,在實際使用時,你只要像下面這樣使用:
1 2 3 4 5 6 |
.selector { width: 150px; height: 64px; /*px*/ font-size: 28px; /*px*/ border: 1px solid #ddd; /*no*/ } |
px2rem
處理之后將會變成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
.selector { width: 2rem; border: 1px solid #ddd; } [data-dpr="1"] .selector { height: 32px; font-size: 14px; } [data-dpr="2"] .selector { height: 64px; font-size: 28px; } [data-dpr="3"] .selector { height: 96px; font-size: 42px; } |
在整個開發(fā)中有了這些工具之后,完全不用擔(dān)心px
值轉(zhuǎn)rem
值影響開發(fā)效率。
rem
前面大家都見證了如何使用rem
來完成H5適配。那么文本又將如何處理適配。是不是也通過rem
來做自動適配。
顯然,我們在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字號是相同的。也就是說,我們不希望文本在Retina屏幕下變小,另外,我們希望在大屏手機(jī)上看到更多文本,以及,現(xiàn)在絕大多數(shù)的字體文件都自帶一些點陣尺寸,通常是16px
和24px
,所以我們不希望出現(xiàn)13px
和15px
這樣的奇葩尺寸。
如此一來,就決定了在制作H5的頁面中,rem
并不適合用到段落文本上。所以在Flexible整個適配方案中,考慮文本還是使用px
作為單位。只不過使用[data-dpr]
屬性來區(qū)分不同dpr
下的文本字號大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
.selector { width: 2rem; border: 1px solid #ddd; } [data-dpr="1"] .selector { height: 32px; font-size: 14px; } [data-dpr="2"] .selector { height: 64px; font-size: 28px; } [data-dpr="3"] .selector { height: 96px; font-size: 42px; } |
為了能更好的利于開發(fā),在實際開發(fā)中,我們可以定制一個font-dpr()
這樣的Sass混合宏:
1 2 3 4 5 6 7 8 9 10 11 |
@mixin font-dpr($font-size){ font-size: $font-size; [data-dpr="2"] & { font-size: $font-size * 2; } [data-dpr="3"] & { font-size: $font-size * 3; } } |
有了這樣的混合宏之后,在開發(fā)中可以直接這樣使用:
1 |
<a href='http://www./members/sanjiaomaohero'>@include</a> font-dpr(16px); |
當(dāng)然這只是針對于描述性的文本,比如說段落文本。但有的時候文本的字號也需要分場景的,比如在項目中有一個slogan,業(yè)務(wù)方希望這個slogan能根據(jù)不同的終端適配。針對這樣的場景,完全可以使用rem
給slogan做計量單位。
本來想把這個頁面的用到的CSS(或SCSS)貼出來,但考慮篇幅過長,而且這么簡單的頁面,我想大家也能輕而易舉搞定。所以就省略了。權(quán)當(dāng)是給大家留的一個作業(yè)吧,感興趣的可以試試Flexible能否幫你快速完成H5頁面終端適配。
最后來看看真機(jī)上顯示的效果吧。我截了兩種設(shè)備下的效果:
其實H5適配的方案有很多種,網(wǎng)上有關(guān)于這方面的教程也非常的多。不管哪種方法,都有其自己的優(yōu)勢和劣勢。而本文主要介紹的是如何使用Flexible這樣的一庫來完成H5頁面的終端適配。為什么推薦使用Flexible庫來做H5頁面的終端設(shè)備適配呢?主要因為這個庫在手淘已經(jīng)使用了近一年,而且已達(dá)到了較為穩(wěn)定的狀態(tài)。除此之外,你不需要考慮如何對元素進(jìn)行折算,可以根據(jù)對應(yīng)的視覺稿,直接切入。
當(dāng)然,如果您有更好的H5頁面終端適配方案,歡迎在下面的評論中與我們一起分享。如果您在使用這個庫時,碰到任何問題,都可以在Github給我們提Issue。我們團(tuán)隊會努力解決相關(guān)需Issues。
|