移動端適配你須要瞭解的那點事

寫在前面

伴隨着移動設備的發展和普及,隨之而來的是躡影追風的網速,這些爲愈來愈豐富的視覺體驗和人性化的交互提供了必要的條件。資深產品、設計也不會放棄展現本身獨特匠心的機會,因此奮戰在一線的前端開發們須要解決的第一個問題----頁面適配。css

一千個用戶看到一千個哈姆雷特的狀況是絕對不容許出現的(最多500個, 哈哈哈)。優雅的方式應該是:展示給用戶的頁面不會因手機品牌、型號、屏幕不一樣,呈現出巨大的差別。最終呈現給用戶的視覺效果應該是相近的。適配多是應對pc和移動端的,也多是針對不用分辨率的還多是。。。(省略1w字)。html

做爲一名前端開發者,頁面適配這個問題曾在一段時間內困擾着我。對於適配咱們須要作些什麼,哪些作法是優雅的,合理的,高效的?前端

下面說一下我的的理解android

預備知識

viewport視口

你有沒有想過,<html>標籤的width屬性 width:20%是指相對那個容器寬度的20%?在調節瀏覽器的寬度的時候html的寬度是怎麼變化的?程序員

其實,viewport就是承載頁面內容的容器,裏面裝載着html,<html>的寬度是相對viewport的 , viewport不是html的概念 不能經過CSS控制。chrome

在PC瀏覽器中viewport嚴格等於瀏覽器的窗口寬高。注意縮放操做不會影響viewport,由於瀏覽器的窗口沒有改變,改變的只是網頁的寬高。瀏覽器

可是在移動設備上有點特殊。由於在設計時,移動設備相對桌面瀏覽器來講寬度太窄了,爲了方便CSS佈局就提出了兩種viewport----visualviewportlayoutviewport,關於這兩種viewport的理解能夠看Stack Overflow上的這篇文章,看完真的有種豁然開朗的感受, 若是堅持不看 接下來要說的可能不是能很好理解。 若是堅持不看 接下來要說的可能不是能很好理解。 若是堅持不看 接下來要說的可能不是能很好理解。sass

須要知道的是這兩種viewport的區別和聯繫。對於移動設備來講,visualviewport就是你經過小窗看到的內容,也就是當前屏幕上顯示的部分,用戶滾動縮放瀏覽器能夠改變visualviewport,可是並不能改變小窗後面的大圖layoutviewport。不幸的是 CSS基本是相對layoutviewport來定義的。因此適配中要作的就是中和visualviewport和layoutviewport帶來影響bash

舉一個默認狀況下的栗子說明:app

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!--<meta name="viewport"-->
          <!--content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">-->
    <title>Viewport</title>
</head>
<body>
<p>this is hasn't viewport</p> </body> </html> 複製代碼

能夠在移動設備上查看 是否設置viewport對顯示效果的影響, 加深對viewport的理解

物理像素

就是設備屏幕上最小的物理部件,每一個物理像素能夠設置本身的顏色和亮度。

CSS像素

這是一個抽象的單位,用來在瀏覽器中精準表示內容大小的屬性,它還有一個更有逼格的名字----設備無關的像素(device-independent pixel)簡稱DIPs, 這個就是.css中所用到的像素

這裏須要知道的是兩個概念的聯繫:開發中接觸的1倍、2倍、3倍屏指的就是一個css像素由多少個物理像素構成,多倍屏是以更多物理像素來展示1個css像素的,更加精細化,顯示效果更棒。

設備獨立像素(density-independent pixel)

表示設備可供程序使用的邏輯像素,最後由系統轉化成對應的物理像素。設置CSS像素時使用的就是這種邏輯像素

設備像素比dpr(device pixel ratio)

這是一個很重要的概念,它定義了設備物理像素和設備獨立像素的對應關係。

公式:

設備像素比 = 物理像素 / 設備獨立像素
複製代碼

這個概念就是移動設備提出的。iPhone4開始,Apple將iPhone4的分辨率提升了一倍,可是物理尺寸沒有發生變化,若是仍是按照已有的方式佈局,將會留出大量空白,顯示效果可想而知。設備像素與設備獨立像素的比例是 1 : 1的時候沒有人關心這個概念,可是如今不一樣了,有了Apple的加入,dpr要多奇葩有多奇葩,這個概念也就顯得十分重要了。

屏幕像素密度PPI(pixel per inch)

能夠理解爲每英寸有多少像素。屏幕像素密度與屏幕尺寸和屏幕分辨率有關,在單一變化條件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小。

rem,em

rem: Relative to font-size of the root element

em: Relative to the font-size of the element

一個是相對根節點一個是相對父節點的沒啥好說的

在真正的理解了這些概念之後,適配就顯得不那麼難了

好了概念介紹完了,咱們偷盜一張圖來輕鬆一下

以最多見的設計稿iPhone6爲栗子,設備獨立像素爲375 * 667, dpr爲2,物理像素爲750 * 1334。 元素CSS樣式:

width: 2px;
height: 2px;
複製代碼

如圖所示在不一樣的屏幕上,CSS像素所呈現的物理尺寸是一致的,而不一樣的是CSS像素所對應的物理像素數不一致。在普通屏幕下1個CSS像素對應1個物理像素,而在Retina屏幕下,1個CSS像素對應的是2個物理像素。

實操

隨着「雜屏」時代的到來,若是你還只是用@media的方式 簡單粗暴的解決問題,我佩服你是個漢子。

設計稿

首先要提到的是設計稿,這個是程序員須要參考的一手資料,也是最終實現效果的參考,在開發中扮演着十分重要的角色,請重視請重視請重視

流程

  • 選擇一種尺寸做爲設計和開發基準(通常就是iPhone6按物理像素標註的版本)
  • 定義一套適配規則,自動適配剩下尺寸
  • 特殊適配效果給出設計效果

這裏要爲廣大開發說一句,一個頁面若是同時用在pc和移動端上,最好最講究的作法是出兩套設計。由於一套設計走天下的背後是開發可能要作不少妥協甚至是黑科技,效果並無想象的那麼好。因此爲了真正上節約你們的時間、少點扯皮的時間,請不要再說看着適配或者是「口口相傳」式的需求,而後反饋適配不完美。

實現

1.設置理想條件viewport

<meta name="viewport" content="width=width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
複製代碼

設置viewport(禁止用戶縮放),讓layoutviewport與visualviewport同樣大(html寬度==屏幕寬度),至於1個CSS像素能夠轉化成多少物理像素由設備決定

2.動態設置viewport縮放

根據dpr不一樣,設置scale爲dpr倒數。 設置scale目的是讓多倍屏1個CSS像素由1物理像素顯示,提供更加精細化控制。回想一下是否遇到過本身畫的1px線比設計稿上的寬,由於你在css文件中設置的1px最後轉換爲物理像素的時候不必定是1px。

這裏可能會有個疑問,既然步驟1已經基本知足適配,爲何還要動態設置viewport縮放?

緣由:

仍是拿iPhone6說,viewport設置縮放爲1的理想viewport,html寬度爲375,顯示的也正好是屏幕 的寬度,這時候1px的CSS像素佔用的2個物理像素,這樣怎麼畫出1物理像素的線?啊?

可是在設置縮放爲0.五、html寬度爲750,縮放後顯示恰好爲屏幕寬度375,而總的CSS像素實際上是750,與設備像素一致,這樣1pxCSS像素佔用的物理像素也是1,完美

3.css單位轉換及適配

設置layoutviewport.widht ==visualviewportscale.width、scale = 1/dpr後,會直接影響css像素最終顯示效果(影響方式點擊查看)。

在iPhone6上,縮放爲0.5,2 CSS px顯示效果爲1px(不理解多看幾遍步驟一、2的解釋),而在scale=1的設備,1 CSS px顯示效果爲1px,不一樣倍數屏幕之間顯示效果存在差別。爲了消除差別、得到一致的顯示效果,須要px適配不一樣dpr的版本。爲此rem登場,用來進行單位適配。

rem理論上能夠是任何正整數,可是考慮到chrome默認root font-size爲16而且最好font-size大於12px,這個rem能夠適當大一點。以iPhone6爲例,我習慣的作法設置rem=75px(將屏幕寬度等分爲100份,一樣符合vh,vw的概念,每10份爲1rem)。

設計稿中標註的75px能夠寫爲1rem
複製代碼

爲了適配不一樣的屏幕須要動態設置根元素fontSize

下面展現下我平時使用的代碼,很久以前寫的 見諒見諒

/**
 * Created by gladyu on 18/7/3.
 */
var ua = navigator.userAgent.toLowerCase();
var is_devices = /iphone/.test(ua) || /ipad/.test(ua) || /android/i.test(ua)
$().ready = adapterRem();
function adapterRem() {
	//rem adapter
	var dpr, rem, scale;
	var docEl = document.documentElement;
	var fontEl = document.createElement('style');
	var metaEl = document.querySelector('meta[name="viewport"]');
	dpr = window.devicePixelRatio || 1;
	if (is_devices) {
		rem = parseFloat(docEl.clientWidth * dpr) / 7.5;
	} else {
		rem = 50;
	}
	scale = 1 / dpr;
	metaEl.setAttribute('content', 'width=' + dpr * docEl.clientWidth + ',initial-scale=' + scale +
		',maximum-scale=' + scale + ',minimum-scale=' + scale + ',user-scalable=no');

	docEl.setAttribute('data-dpr', dpr);
	docEl.firstElementChild.appendChild(fontEl);
	fontEl.innerHTML = "html{font-size:" + rem + "px!important;}";
	console.log(rem);
	window.dpr = dpr;
	window.rem = rem;
};

複製代碼

只是給你們提供一下思路,確定比我寫的好。步驟1,2,3須要在你引入css文件以前完成,這樣css中的rem纔是你指定的呀

4.rem計算

在面對設計稿中衆多須要轉換px到rem的操做,心算是確定不行的,爲了方便,能夠藉助sass寫一個函數計算px轉化爲rem。這樣在寫樣式時就不用手動計算,直接調用函數就行了。

@function px2em($px, $base-font-size: 16px) {
    @if (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;
}

font-size: px2rem(18px);
複製代碼

至此,你須要作的就是切頁面完成需求了

文本字號不建議rem

絕大多數的字體文件都自帶一些點陣尺寸,比較常見的一般是16px和24px,使用rem會出現不少奇葩尺寸。再就是咱們但願在不一樣屏幕上字體大小看起來是相近的,在大屏上能夠顯示更多文字。

如此一來,rem並不適合用到文字上, 仍是使用px做爲單位。使用dpr屬性來設置不一樣dpr下的文本字號大小。

本身的作法是根據dpr設置body的字體大小,其餘的元素字體單位使用em,這樣只須要改變body的fontSize其餘的就跟着改變了。

這是我在不引入框架時解決適配問題的方式,但願能夠幫到你 若是你還有更好的方案 歡迎交流

轉載必須標明出處,謝謝。文章有疏漏淺薄之處,請各位大神斧正

相關文章
相關標籤/搜索