1. 程式人生 > >移動端適配方案-讓解析度來的更猛烈些吧!

移動端適配方案-讓解析度來的更猛烈些吧!

前言

公司許多的業務都還停留在使用px和彈性佈局來進行樣式處理的階段,有些時候是因為視覺要求,有些時候是害怕線上問題,所謂破而後立。

移動端適配方案是一個老生常談的話題,但是對於不同的專案、不同的業務場景可能會需要不同的適配方案來進行移動端適配,向下相容的baseline也需要提前訂好。

整體寬高

其實移動端適配就和下面的玩具一樣,對應的形狀塞到對應的容器裡面就好了。但是有點小小的問題,就是這些積木的大小可能和容器不太一樣,對於前端來說,這些積木不是用木頭做的,而應該是用橡皮泥做的。

形狀玩具

業務環境是決定整體專案的適配方案的核心因素。一套程式碼到底需要相容多少環境是在專案開始架構的時候就需要確定的。

世界最大程式設計師交友網站,github web端主站可以明顯的看到,所有的內容都被限制到了一個980畫素的內容區域裡面。

而其移動端也也很明顯的是一個單獨的佈局方式,整體寬度不再限制,即使到了iPad Pro這種寬度到達1024畫素的裝置上,仍然會佔滿整個螢幕。

而淘寶的主站和github類似,分為移動端頁面和PC端頁面,PC端頁面同樣有著左右的留白,這也是為了讓使用者能夠在寬屏的時候將注意力集中在中間區域。

當前大部分站點都採用UA來判斷使用者的裝置,然後定向到PC或者H5頁面。

兩者的唯一不同點在於:淘寶會更加嚴格地將頁面直接重定向到另外一個連結,而github則是載入了一個不同的CSS檔案進行渲染。當然,這兩種方案其實沒有本質的差別,而單獨的H5頁面可以在客戶端站內進行更好地複用

所以,如果有足夠的開發人員,開發適用於兩種裝置型別的頁面是比較友好的方案。如果你的移動客戶端是基於webview開發的話,那麼H5頁面還可以直接嵌入到webview中作為展示。

寬度適應

對於整體寬度,正常移動裝置的寬高比都比較協調,而像iPad這種裝置,其寬度過大,導致了正常的H5頁面在上面顯示會有比較奇怪的效果。比如淘寶的主站在iPad上的顯示效果,可以看到上下兩塊的navigator被拉長了很多,導致了效果不好。但是如果考慮到成本問題,iPad使用者更多地會使用APP來進行訪問,所以H5頁面的樣式重要性就被縮減了。而github移動版對於寬屏裝置的適配就會做得更好。

有興趣的話,可以去看看

淘寶的H5頁面,這個頁面有一個很有趣的地方,這個地方後文會講到,這裡先提一下:

淘寶H5 header

除了寬度仍舊佔滿螢幕寬度的方案,設定螢幕的最大寬度可以保證在寬屏裝置上的顯示效果,但是留白的部分就需要考慮處理方案。

由於有了固定最大寬度,僅僅需要對於超過寬度的具有留白的裝置進行特殊處理(可以是背景、功能按鈕等),中間具有最大寬度的部分就可以進行程式碼複用。

視口

考拉團隊的這篇blog寫的已經非常清楚了,感謝考拉的小夥伴給我們提供了便宜的海淘還有這麼好的文件產出lol:

PC

桌面瀏覽器中,正常的視口寬度就是整個瀏覽器的視窗寬度,會隨著瀏覽器視窗的伸縮而縮放。預設情況下HTML標籤會佔滿整個視口,如果沒有設定HTML的靜態width的話。

如果採用之前所述的,PC端頁面設定最大寬度的話,那麼當視口在最大寬度之外的時候縮放的話,不會影響可見區域的顯示效果,但是如果縮小到比最大寬度小的時候,原頁面的佈局方案就很重要了。彈性佈局和百分比的佈局方式能夠在頁面縮小的時候,保證頁面的佈局不會崩潰。

佈局視口

在手機上,視口與移動端瀏覽器的寬度不再關聯,而是完全獨立的了。我們稱其為佈局視口。

整個頁面可能會變得很大,然後只有一部分顯示在裝置的可見區域內,整個頁面的大小叫做Layout Viewport。這個大小可以通過document.documentElement.clientHeight/clientWidth來獲取。

PPK這篇很早的文章對於視口進行了非常清晰的描述。

Layout Viewport

上圖可見,Layout Viewport的寬高其實是可變的,當通過手勢縮放頁面的時候,Layout Viewport就會發生變化,當頁面縮放到和裝置的可見區域大小一致的時候,Layout Viewport就剛好等於Visual Viewport了。

可見視口

Visual Viewport其實很好理解,就是整個螢幕的可見區域大小。由於裝置的物理畫素,也就是CSS中的pt單位是固定的,頁面在移動端被縮放了之後,頁面中的CSS畫素分佈在裝置上也發生了變化。

理想視口

Ideal Viewport其實是上面兩者的結合,當我們將Layout Viewport的寬度設定成螢幕的寬度,就保證了頁面中CSS畫素點的恆定。

這裡就用到了移動端適配常用的<meta name="viewport" content="width=device-width">

這個標籤可以保證在移動端裝置中,頁面的寬度與螢幕寬度相同。

縮放

在手機上進行放大的時候,頁面中的CSS畫素不變,但是可見視口的畫素比例發生了變化,但是禁用縮放會導致某些使用者的體驗較差。保持縮放比例在一定範圍之內比較合適。

整體佈局

基於如上所述的內容,結合目前的業務內容--主要針對移動端裝置進行適配,採用設定最大寬度,並且在meta標籤中設定理想視口,可以保證在移動裝置以及PC上面的整體佈局效果。

內容佈局

目前對於移動端適配的內容佈局效果是這樣的:

  • 百分比,所有需要動態調整的元素寬高採用百分比,字號固定畫素。
  • rem,通過計算或者JavaScript獲取到裝置畫素/CSS畫素的比例,確定根元素的字型畫素,然後所有單位根據根元素字型畫素進行rem設定,確定大小。而基礎rem會根據裝置變化而變化。
  • vw,根據當前裝置的Visual Viewport寬度作為100vw,然後得出單位vw的寬度,所有元素按照vw為單位進行樣式排布。
  • Media Query:通過斷點來進行不同寬度區間的裝置樣式適配。

以上幾個方法各自都有各自的好處,我們可以看一下實際應用時候的效果:

百分比

使用百分比作為內容大小的標準,在大部分條件下是可行的,百分比可以很好地讓元素乖乖呆在自己的位置,無論螢幕的寬度大小。

但是文字就存在非常大的問題了,由於文字是固定大小,在螢幕dpr變化的時候,文字的CSS畫素不變,就導致了文字在頁面中的佔位發生了變化。這樣的結果就是,文字過多或者螢幕dpr過小的時候,會發生溢位;但是如果按照小螢幕為基準,又會發生字型太小這種情況。

百分比在當前移動端適配排版的時候,更多地會作為section級別元素的相容排版。這個也要和設計稿中的效果相關,如果設計稿中要求一個元素定寬,那麼就直接用px來保證寬度就可以了。

rem

rem這個單位和之前常用的em有點類似,唯一的區別在於rem及基於根元素的font-size來進行計算的一個相對值。em存在很多缺點,比如層層巢狀之後,可能就會忘記了上一層的font-size到底是多大。或者比如像現在的模組化開發,一個路由套在另一個路由裡面,甚至找父元素都需要到其他檔案中去找。

為了解決em存在的問題,標準中還有rem這個單位來幫助排版。所有的元素大小都用rem來作為單位,然後在頁面的根元素中,我們為根元素的font-size進行確定化地賦值,這樣所有的rem單位都是同一個明確的基準了。當螢幕進行適配的時候,只需要調整這個基準值,就可以保證每個元素的大小自動按照比例調整。

阿里的lib-flexible解決方案實際上就是利用了這個方式,通過給<html>標籤繫結font-size以及data-dpr屬性來進行整個頁面的適配。

方案將整個頁面寬度分成100份,分成100份的原因可以看下面的另一個方案。每10個單位寬度作為1rem,也就是整個視覺稿的寬度會被分成10rem的100份,假如拿到的視覺稿是750px的,那麼1rem就代表75px。這樣得到的比例係數就是75/750,也就是每次在進行設計稿到CSS的轉換的時候,只需要對設計稿的畫素值/10就可以得到對應的rem值。

通過一個預先載入的JavaScript指令碼,計算根節點的字型大小,document.documentElement.style.fontSize = window.innerWidth / 10 + 'px';,然後我們在寫頁面程式碼的時候只需要將原始的畫素值/基準值就可以得到對應的rem單位了。當然每次都要按計算器肯定是不行的。如果想方便使用的話,可以用less或者sass這種前處理器來處理頁面。

@function px2rem($px)
  // 這裡將設計稿的px轉換為rem,
  @return ($px / $unit-px) * 1rem
// 根據裝置的dpr進行字型適配
@mixin font-dpr($font-size) 
    font-size: $font-size
    [data-dpr="2"] &
		font-size: $font-size * 2
複製程式碼

除了元素寬高可以得到比較好的還原,對於文字大小的適配也比較重要,由於每個裝置的dpr不同(這裡尤其是iOS裝置),直接導致了很多文字在iPhone6+上顯示正常,而在iPhone5上面卻文字過大,導致文字溢位,上面的less mixin就是進行字型樣式適配的。

這種方法結合了sass的函式功能和rem的適配,再加上必要的百分比以及media query可以得到比較好的移動表現。

這是使用這種方法在iphone6上的顯示效果,具體的整體顯示效果可以戳這裡,rem基準樣式示例

如果對於文字在各種平臺上的顯示效果不滿意,可以通過上面說的sassmixin來讓文字根據dpr進行斷點渲染。

而這樣存在的問題就是僅僅適用於移動端,並且不能夠進行橫屏適配,因為橫屏之後,頁面的寬度發生了變化,但是基準值卻還保持著原本繫結到根節點上面的基準值。

vw(是最終解決方案嗎?)

首先看看vw的瀏覽器支援情況吧,can i use vw支援情況,使用這個單位意味著你放棄了IE11以下的PC使用者,在現在一個主要相容移動端的世界裡,並沒有太大的副作用(這裡吐槽一句,其實PC端的相容遠遠要比移動端來的方便。移動端奇奇怪怪的解析度以及2x,3x的螢幕,還有苦逼的ipad、橫屏讓我每次做相容的時候想一躍解千愁)。

vw自身將整個可見視口橫向分成了100份,每一個單位就是1vw,這個單位最大的優勢就是在移動端的時候,無論是豎屏或者橫屏,vw永遠都是針對於橫向的,比rem的方案好在當螢幕大小發生變化(順便相容了以後的可調節螢幕大小的移動裝置[手動斜眼])的時候,不會讓頁面崩掉。

對於移動裝置來說,比如iphone6+的375pxCSS畫素寬度,1vw就等於3.75px,通過這個單位可以解決上面的依賴於指令碼繫結根元素font-size的問題,在豎屏和橫屏下面都有比較好的效果。

在通過vw解耦了CSS和JS之後,那麼vw是否可以獨立解決所有問題呢?

// 首先,我司的設計稿目前都是以750px為寬度,實際為iPhone6+的375px為基準
$w-base: 375px
$w-base-design: 750px
@function px2vw($px)
    @return ($px / $w-base-design) * 100vw
複製程式碼

首先,上面的sass程式碼可以根據你設計稿上面的px單位轉換為vw單位值。當然最簡單的辦法還是直接按照視覺稿上面畫素進行輸入,然後直接輸出對應的vw值啦。vscode和sublime當然會有已經做好的外掛,但是個人並不是很喜歡這種方式,這樣你就沒辦法得到這個視覺稿原本的畫素值了。在後期進行維護的時候會增加很多很多很多麻煩。這就是寫起來爽,改起來火葬場吧。。。vw的效果可以看下面的codepen。

vw實現的同樣適配頁面

所以說優勢和劣勢呢

目前來說,vw是肯定不適合單獨使用的,畢竟頁面中還是有很多元素需要絕對的大小定位的。px永遠是必不可少的,視覺不可能讓你所有的東西都自適應。

那麼vw能夠解決什麼問題呢?首先是大部分取代%在CSS中的使用,百分比在CSS中存在很多歧義,對於寬度,上下邊距,左右邊距,內外邊距的處理方式不盡相同。即使是老練的前端有時候也得思考一下當前的百分比到底是根據什麼確定的。而vw則是一個絕對的數值,僅僅根據一個不太可能變化的螢幕寬度來確定。

而百分比主要解決的彈性問題,就是vw著力解決的問題。

vw不能夠兼顧所有的情況,所以這個單位目前還並不是最終的解決方案,還是需要和其他單位合作來幫助頁面能夠更加優雅地顯示出來。

結論

CSS的相容性不在於直譯器上,而是在於裝置的螢幕上面。大部分時間不僅需要將頁面展示在使用者的面前,而是需要將頁面穩定且優雅地展示給使用者。

無論是百分比,rem還是vw,都是進行區域性容器元素定位的,作為最底層的葉子元素或者單元元素來說,更多時間還是會使用px來儘量還原視覺稿。

長遠考慮這個問題,vw在僅進行移動端訪問的情況下效果拔群,因為不考慮相容,只需要考慮適配問題。工程中到底使用哪個方法進行,取決於大部分業務需要相容的環境。