Flexible到今天也有幾年的歷史了,解救了很多同學針對於H5頁面布局的適配問題。而這套方案也相對而言是一個較為成熟的方案。簡單的回憶一下,當初為了能讓頁面更好的適配各種不同的終端,通過Hack手段來根據設備的dpr值相應改變<meta>標簽中viewport的值:
從而讓頁面達么縮放的效果,也變相的實現頁面的適配功能。而其主要的思想有三點:
- 根據
dpr的值來修改viewport實現1px的線 - 根據
dpr的值來修改html的font-size,從而使用rem實現等比縮放 - 使用Hack手段用
rem模擬vw特性
有關於Flexible方案實現適配,在2015年雙十一之后做過這方面的技術文檔分享,感興趣的同學可以移步閱讀《使用Flexible實現手淘H5頁面的終端適配》一文。雖然Flexible解決了適配終端很多問題,但它並不是萬能的,也不是最優秀的,他還是存在一些問題的,比如iframe的引用,有時候就把我們自己給埋進去了。針對其中的一些不足之處,有些同學對其進行過相關的改造,在網上搜索能找到相關的方案。
那么時代在變化,前端技術在不斷的變化,試問:Flexible還是最佳方案?Flexible還有存在的必要嗎? 最近一直在探討這方面,這里先告訴大家Flexible已經完成了他自身的歷史使命,我們可以放下Flexible,擁抱新的變化。接下來的內容,我將分享一下我最近自己探討的新的適配方案,或許很多團隊同學已經開始使用了,如果有不對之處,希望能得到大嬸們的指正;如果您有更好的方案,希望能一起分享一起探討。
先上菜,再嘮嗑
先上個二維碼:

你可以使用手淘App、優酷APP、各終端自帶的瀏覽器、UC瀏覽器、QQ瀏覽器、Safari瀏覽器和Chrome瀏覽器掃描上面的二維碼,您看到相應的效果:

iPhone系列效果

部分Android效果
注:如果掃上面的二維碼沒有任何效果,你可以點擊這里,打開在線頁面,重新生成你的設備能識別的二維碼號 。
上面的Demo,測試了Top30的機型。目前未得到支持的:
| 品牌 | 型號 | 系統版本 | 分辨率 | 屏幕尺寸 | 手淘APP | 優酷APP | 原生瀏覽器 | QQ瀏覽器 | UC瀏覽器 | Chrome瀏覽器 |
|---|---|---|---|---|---|---|---|---|---|---|
| 華為 | Mate9 | Android7.0 | 1080 x 1920 | 5英寸 | Yes | Yes | No | Yes | Yes | Yes |
| 華為 | Mate7 | Android4.2 | 1080 x 1920 | 5.2英寸 | Yes | Yes | No | Yes | Yes | Yes |
| 魅族 | Mx4 (M460 移動4G) | Android4.4.2 | 1152 x 1920 | 5.36英寸 | Yes | No | No | Yes | Yes | Yes |
| Oppo | R7007 | Android4.3 | 1280 x 720 | 5英寸 | Yes | No | No | Yes | Yes | No |
| 三星 | N9008 (Galaxy Note3) | Android4.4.2 | 1080 x 1920 | 5.7英寸 | Yes | No | Yes | Yes | Yes | Yes |
| 華碩 | ZenFone5(x86) | Android4.3 | 720 x 280 | 5英寸 | No | No | No | Yes | No | No |
Top30機型中不在列表中的,將看到的效果如上圖所示。至於敢不敢用,這就得看親了。必竟第一個吃螃蟹的人是需要一定的勇氣!(^_^)
適配方案
前面給大家介紹了這個方案目前得到的支持情況以及效果。也扯了不少廢話,接下來進入正題吧。
在移動端布局,我們需要面對兩個最為重要的問題:
- 各終端下的適配問題
- Retina屏的細節處理
不同的終端,我們面對的屏幕分辨率、DPR、1px、2x圖等一系列的問題。那么這個布局方案也是針對性的解決這些問題,只不過解決這些問題不再是使用Hack手段來處理,而是直接使用原生的CSS技術來處理的。
適配終端
首要解決的是適配終端。回想一下,以前的Flexible方案是通過JavaScript來模擬vw的特性,那么到今天為止,vw已經得到了眾多瀏覽器的支持,也就是說,可以直接考慮將vw單位運用於我們的適配布局中。
眾所周知,vw是基於Viewport視窗的長度單位,這里的視窗(Viewport)指的就是瀏覽器可視化的區域,而這個可視區域是window.innerWidth/window.innerHeight的大小。用下圖簡單的來示意一下:

因為Viewport涉及到的知識點很多,要介紹清楚這方面的知識,都需要幾篇文章來進行闡述。@PPK大神有兩篇文章詳細介紹了這方面的知識。中文可以移步這里進行閱讀。
在CSS Values and Units Module Level 3中和Viewport相關的單位有四個,分別為vw、vh、vmin和vmax。
vw:是Viewport's width的簡寫,1vw等於window.innerWidth的1%vh:和vw類似,是Viewport's height的簡寫,1vh等於window.innerHeihgt的1%vmin:vmin的值是當前vw和vh中較小的值vmax:vmax的值是當前vw和vh中較大的值
vmin和vmax是根據Viewport中長度偏大的那個維度值計算出來的,如果window.innerHeight > window.innerWidth則vmin取百分之一的window.innerWidth,vmax取百分之一的window.innerHeight計算。
還是用一張圖來示意吧,一圖勝於千言萬語:

所以在這個方案中大膽的使用vw來替代以前Flexible中的rem縮放方案。先來回歸到我們的實際業務中來。目前出視覺設計稿,我們都是使用750px寬度的,從上面的原理來看,那么100vw = 750px,即1vw = 7.5px。那么我們可以根據設計圖上的px值直接轉換成對應的vw值。看到這里,很多同學開始感到崩潰,又要計算,能不能簡便一點,能不能再簡單一點,其實是可以的,我們可以使用PostCSS的插件postcss-px-to-viewport,讓我們可以直接在代碼中寫px,比如:
PostCSS編譯之后就是我們所需要的帶vw代碼:
在實際使用的時候,你可以對該插件進行相關的參數配置:
假設你的設計稿不是750px而是1125px,那么你就可以修改vewportWidth的值。有關於該插件的詳細介紹,可以閱讀其官方使用文檔。
上面解決了px到vw的轉換計算。那么在哪些地方可以使用vw來適配我們的頁面。根據相關的測試:
- 容器適配,可以使用
vw - 文本的適配,可以使用
vw - 大於
1px的邊框、圓角、陰影都可以使用vw - 內距和外距,可以使用
vw
另外有一個細節需要特別的提出,比如我們有一個這樣的設計:

如果我們直接使用:
最終的效果會造成[w-187-246]容器的高度小於[w-188-246]容器的高度。這個時候我們就需要考慮到容器的長寬比縮放。這方面的方案很多,但我還是推薦工具化來處理,這里推薦@一絲 姐姐寫的一個PostCSS插件postcss-aspect-ratio-mini。這個插件使用很簡單,不需要做任何的配置,你只需要本地安裝一下就OK。使用的時候如下:
編譯出來:
這樣就可以完美的實現長寬比的效果。有關於這方面的原理在這里不做過多闡述,感興趣的話可以閱讀早前整理的文章:
目前采用PostCSS插件只是一個過渡階段,在將來我們可以直接在CSS中使用
aspect-ratio屬性來實現長寬比。
解決1px方案
前面提到過,對於1px是不建議將其轉換成對應的vw單位的,但在Retina下,我們始終是需要面對如何解決1px的問題。在《再談Retina下1px的解決方案》文章中提供了多種解決1px的方案。在這里的話,個人推薦另外一種解決1px的方案。依舊是使用PostCSS插件,解決1px可以使用postcss-write-svg。
使用postcss-write-svg你可以通過border-image或者background-image兩種方式來處理。比如:
這樣PostCSS會自動幫你把CSS編譯出來:
使用PostCSS的插件是不是比我們修改圖片要來得簡單與方便。
上面演示的是使用border-image方式,除此之外還可以使用background-image來實現。比如:
編譯出來就是:
這個方案簡單易用,是我所需要的。目前測試下來,基本能達到我所需要的需求。但有一點千萬別忘了,記得在<head>中添加:
上面闡述的是這個適配方案中所用到的技術點,簡單的總結一下:
- 使用
vw來實現頁面的適配,並且通過PostCSS的插件postcss-px-to-viewport把px轉換成vw。這樣的好處是,我們在擼碼的時候,不需要進行任何的計算,你只需要根據設計圖寫px單位 - 為了更好的實現長寬比,特別是針對於
img、vedio和iframe元素,通過PostCSS插件postcss-aspect-ratio-mini來實現,在實際使用中,只需要把對應的寬和高寫進去即可 - 為了解決
1px的問題,使用PostCSS插件postcss-write-svg,自動生成border-image或者background-image的圖片
這里使用了多個PostCSS的插件,其實現在有很多優秀的PostCSS插件能幫助我們解決很多問題。哪果你從未接觸過有關於PostCSS相關的知識,建議你可以花點時間去學習一下,在W3cplus提供了一些有關於PostCSS相關的文章。如果你想系統的學習PostCSS相關的知識,推薦你購買《深入PostCSS Web設計》一書:

降級處理
最開始提到過,到目前為止,T30的機型中還有幾款機型是不支持vw的適配方案。那么如果業務需要,應該怎么處理呢?有兩種方式可以進行降級處理:
- CSS Houdini:通過CSS Houdini針對
vw做處理,調用CSS Typed OM Level1 提供的CSSUnitValueAPI。 - CSS Polyfill:通過相應的Polyfill做相應的處理,目前針對於
vw單位的Polyfill主要有:vminpoly、Viewport Units Buggyfill、vunits.js和Modernizr。個人推薦采用Viewport Units Buggyfill
Viewport不足之處
采用vw來做適配處理並不是只有好處沒有任何缺點。有一些細節之處還是存在一定的缺陷的。比如當容器使用vw單位,margin采用px單位時,很容易造成整體寬度超過100vw,從而影響布局效果。對於類似這樣的現象,我們可以采用相關的技術進行規避。比如將margin換成padding,並且配合box-sizing。只不過這不是最佳方案,隨着將來瀏覽器或者應用自身的Webview對calc()函數的支持之后,碰到vw和px混合使用的時候,可以結合calc()函數一起使用,這樣就可以完美的解決。
另外一點,px轉換成vw單位,多少還會存在一定的像素差,畢竟很多時候無法完全整除。
到目前為止,我發現的兩個不足之處。或許在后面的使用當中,還會碰到一些其他不為人之的坑。事實也是如此,不管任何方案,踩得坑越多,該方案也越來越強大。希望喜歡這個適配方案的同學和我一起踩坑,讓其更為完善。
如何判斷自己的應用是否支持
雖然該文的示例,進行了多方面的測試。但很多同學還是會擔憂自己的APP應用是否支持該方案,而不敢大膽嘗試或者使用。其實不必要這么擔心,你可以拿自己的設備,或者應用掃描下面的二維碼:

當頁面跑完測試之后,找到對應的Values and Units列表項:

如果vw欄是綠色代表你的設備或應用支持該方案;反之則不支持。另外你也可以經常關注css3test相關的更新,后面將會根據相關的規范更新測試代碼,讓你能快速掌握哪些屬性可以大膽使用。
總結
H5頁面的適配方案總是令人蛋疼的,事實上頁面的布局總是令人蛋疼的。但技術是不斷革新的,我們可以隨着保持對新技術的關注,嘗試這些新特性運用到實際項目中,只有這樣,我們解決問題的方案才會越來越完善。
到寫這篇文章為止,雖然還有那么一兩款機型不支持vw,但並不影響我們去使用。只有不斷去嘗試,才會有進步。在此,希望大家大膽嘗試,一起讓該方案變得更完美。如果你有更好的建議,或者你踩到任何坑,歡迎在下面的評論中與我分享,或者發郵件給我一起討論。
著作權歸作者所有。
原文: https://www.w3cplus.com/css/vw-for-layout.html © w3cplus.com
