1. 程式人生 > >移動端的適配

移動端的適配

網頁移動端適配的胡亂分析

由viewport到移動端頁面適配

  如果你想認真仔細地瞭解可以看看這一篇部落格
  對於viewport,字面意思是視口,也就是我們正常能看見的視窗。有大神把viewport分為layout viewport(瀏覽器預設的viewport,基本大於瀏覽器可視區域), visual viewport(瀏覽器的可視區域) 和 ideal viewport(移動裝置理想的viewport)。為什麼會這麼麻煩呢?
  這就要提到畫素(px)了。css中的1px和事實上的1px其實並不相同。mdn上邊說的是A pixel is not a pixel,畫素並非畫素。嗯,有點複雜。其實也沒那麼複雜。css裡邊的px是一個相對的概念,在移動裝置上,如果螢幕畫素密度很高,而css和物理畫素依然是一比一的關係的話,那麼我們視覺上是沒法看清網頁的。所以如果螢幕畫素密度很高,基本上一個css畫素會對應幾個物理畫素。
而這是現在,以前手機上的解析度不高的時候,在我們還活在諾基亞支配的恐懼下的時候(ps:這裡沒有貶它的意思,畢竟那個時代能做到那樣已經很不錯了),我們用的是wap來實現手機上的網頁,功能有限。直到蘋果出來了,蘋果改變了移動終端瀏覽網頁的方式,使得html可以在移動端展示。但是初代iPhone螢幕是3.5英寸,解析度為480*320,為了讓使用者有更好的瀏覽體驗(至少能把頁面顯示完全),iPhone預設把你的頁面的viewport設定為980px(也就是layout viewport),這樣我們就可以通過滑來滑去來瀏覽那些為電腦設計的網頁了。
  所以這就直接導致了不論我們的解析度多高只要這個網頁沒有適配移動端那麼我們極有可能看到的是一個佈局完全錯亂的網站,因為移動端真正的viewport(也就是可視區域,visual viewport)不夠寬。鑑於隨著科技的發展,越來越多的網站都會為移動裝置進行單獨的設計,這個可以完美適配移動裝置的viewport,稱為ideal viewport。
  對於開發者而言,做移動端的適配的話當然離不開ideal viewport了,而移動裝置瀏覽器預設的viewport是layout viewport(那個比螢幕寬的),如果想要得到ideal viewport,需要用到html的meta標籤。
  快捷鍵:meta:vp


<meta name="viewport" content="width = device-width, initial-scale = 1.0, user-scalable = no">
  width: 設定的是layout viewport的寬度,可以為正整數,為device-width的時候表示等於裝置的寬度。
  initial-scale: 設定頁面的縮放值,是一個數字。如果為1.0的話表示不進行縮放,完全適配移動端。也就是說,縮放為1.0的話表示此時的ideal viewport和layout viewport是相等的。
  user-scalable: 設定使用者是否可以進行縮放。yes表示可以,no表示不可以。
  除了上邊的三個之外,content裡邊還可以設定minimum-scale(允許使用者的最小縮放值),maximum-scale(允許使用者的最大縮放值)和height(基本不用的引數)。
  在使用的時候,width = device-width
initial-scale = 1.0可以達到同樣的效果,但是在不同的裝置上兩個屬性的相容性不同,所以為了保險起見一般會把兩句都加上。
  獲取visual viewport寬度:window.innerWidth
  獲取layout viewport寬度:document.documentElement.clientWidth
  當它們的比例為一比一的時候,就是ideal viewport。

由媒體查詢到移動端適配

  @media是寫在同一個css檔案中的查詢條件,當裝置符合某個媒體查詢條件的時候裡邊的css生效。
  用@media的時候注意覆蓋的問題,比如下邊的情況

@media(max-width: 320
px)
{
background: red; } @media(max-width: 375px){ background: black; }

  此時background: red並不會生效,因為max-width: 375px包括max-width: 320px,並且它寫在後邊,所以會覆蓋前邊的。
  如果你不想它被覆蓋可以把範圍小的寫在下邊。或者讓它們沒有交集,比如這樣

@media(min-width: 0) and (max-width: 320px) { background: red; }
@media(min-width: 321px) and (max-width: 375px) { background: black; }

  除了@media之外你也可以直接在link檔案的時候執行查詢條件,比如<link rel="stylesheet" rel="style.css" media="(max-width: 320px)">。這裡需要注意的是雖然我們在請求的資源裡進行了查詢,但其實就算顯示的裝置不滿足查詢條件,這個css檔案也一樣會下載。只是不生效而已。
  所有的響應式網站用的都是媒體查詢,一個典型的響應式網站在這裡,事實上響應式不過是你做了兩版網頁,一個用於PC端一個用於移動端。如果你選擇移動端優先,那就是選擇了方案Mobile first,PC端優先就是Desktop first了(emmm為什麼要整個專業名詞)。
  響應式基本上是通過元素的隱藏和顯示來實現,對css進行各種覆蓋。實際開發中很少會用到響應式,比如淘寶和京東都是通過後臺判斷,給你進行重定向到另一個地方,而知乎是選擇展示另一個網頁。

由rem到移動端適配

網頁單位
  rem可以說是專為移動端網頁開發準備的一個單位了。網頁開發中的單位包括有我們常見的px,em,vh,vw,百分比,rem等等。px是絕對畫素單位。em是一個相對長度單位,一般說來1em指的是一個font-size的寬度,你可以簡單的記成一個字母M的寬度。vh(viewport height)和vw(viewport width)分別是相對於視口的高度和寬度,比如100vh就是視口的高度。其實到這裡已經夠了,我們可以用vw做相容性很好的手機頁面。但是vw的相容性太差,所以不得不放棄這個方案。而百分比的話雖然可以保證寬度的良好縮放比,但不能保證高度具有同樣的效果,如果你需要一個元素的寬高在縮放的時候也保持著相同的比例,那你就不得不放棄這個方案。而我們要說的rem,是一個在保證相容性的情況下也能保證長寬比的一個方案。rem(root em)是相對於根元素的大小來確定自己本身的大小,這裡的根元素,指的是html元素而不是body。
常識相關
  需要注意的是瀏覽器預設字型大小是16px,也就是說如果你不寫font-size的話,那麼它的font-size就是16px。
  以及,Chrome瀏覽器的最小字號是可以在瀏覽器的設定裡邊手動設定的,如果沒有修改的話那麼預設最小字號是12px。也就是說,如果你設定font-size: 6px;顯示出來的結果依然是12px。
  以及,網頁顯示的最小單位是1px,小於1px的都會按照1px來顯示。
正文
  一切單位以寬度為基準就可以很好地還原設計圖,因為高度是可以滑動的。但是隻有vw是以寬度為基準的,而它的相容性不好所以被我們棄用。這裡的主角rem同樣與寬度無關,但是我們可以讓它變得與寬度有關。
  我們知道js可以為html新增元素,所以我們用js來動態獲取頁面的viewport,讓1rem === 1vw

var width = window.innerWidth/100
document.write('<style>html{font-size: '+ width +'px}<style>')

  但是這樣寫的話你就犯了一個常識性錯誤。Chrome的最小字號預設是12px。你這樣設定的話,1rem很有可能小於12px,這樣佈局是會錯亂的。所以保險起見除以10就夠了,把視口的寬度分為十份來進行佈局。
  這是一個簡單的網頁示例。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <script>
    var width = window.innerWidth/10
    document.write('<style>html{font-size: '+ width +'px}<style>')
  </script>
  <style>
  *{  margin: 0; padding: 0;  }
  body{  margin: 0; padding: 0; font-size: 16px;  }
  .child{
    float: left;
    background: #ddd;
    width: 4rem;
    height: 2rem;
    margin: .5rem .5rem;
  }
  .clearfix::after{
    content: '';
    display: block;
    clear: both;
  }
  </style>
</head>
<body>
<div class="parent clearfix">
  <div class="child">box</div>
  <div class="child">box</div>
  <div class="child">box</div>
  <div class="child">box</div>
</div>
</body>
</html>

  在我們使用熱門佈局的時候,並不意味著px等其它的單位就不可用了,事實上,為了更好地完成一個網頁。你可以將他們混著用。因為有的時候螢幕如果很小的話,由rem計算出來的字型或者什麼的可能就看不清楚了,這個時候還不如用px這種絕對單位。
將px轉換成rem
  如果用rem的話我們需要手動計算rem的值,很麻煩。眾所周知程式設計師都很懶,所以使用sass可以很好的幫你解決這個問題。
1. 安裝sass

npm config set registry https://registry.npm.taobao.org/
touch ~/.bashrc
echo 'export SASS_BINARY_SITE="https://npm.taobao.org/mirrors/node-sass"' >> ~/.bashrc
source ~/.bashrc
npm i -g node-sass

  鑑於國內上網的諸多限制所以我們沒法直接用命令npm i -g node-sass來安裝,只能先把下載源設定為淘寶映象然後再執行下載。這種安裝的是node-sass。你也可以安裝ruby-sass。
2. 使用scss的函式將px轉換成rem
  tips: SCSS是Sass3引入的新的語法。
  先建立style.scss檔案和style.css檔案。
  然後開啟自動轉換,如果你是node-sass的話,請使用node-sass -wr style.scss -o style.css,如果是ruby-sass的話,使用sass --watch style.scss:style.css。開啟之後不要動它。
  在style.scss檔案中寫下這段程式碼。

@function px2rem( $px ){
  @return $px/$designWidth*10 + rem;
}
$designWidth = 640;  //設計稿的寬度

  然後就可以直接在style.scss檔案裡用px2rem(不加單位的畫素值)了,sass服務會幫我們把它的值計算出來並寫入css檔案。

最後需要注意的一點東西

  1. 移動端沒有click事件,沒有hover,有touch。很多框架都封裝了touch實現的滑動事件(swiper)。所以一般不監聽click和hover。
  2. 手機上沒有滾動條。