移動端H5解惑-頁面適配(二)

本文原文發表於2016年個人github,可是直到如今爲止還有不少童鞋問我相關概念,因而整理下再分享一下。css

原文連接:github.com/sunmaobin/s…html

1、基礎概念

在瞭解如何作H5頁面適配前,你們都應該把移動端涉及的一些概念搞明白,好比:dpr 是什麼意思?vue

移動端H5解惑-概念術語(一)css3

2、爲何要作頁面適配

2.1 PC端爲何要解決瀏覽器兼容

由於在PC端,因爲瀏覽器種類太多啦,好比幾個經常使用的:IE、火狐、Chrome、Safari等。同時,因爲歷史緣由,不一樣瀏覽器在不一樣時期針對當時的WEB標準有一些不同的處理(雖然大部分同樣),好比:IE六、IE八、IE10+等對於一些JS事件處理、CSS樣式渲染有所不一樣。git

而偏偏又有一些人在使用着不一樣類型的瀏覽器,以及不一樣瀏覽器的不一樣版本。因此,爲了能讓你的網站讓這些不一樣的人看到效果一致,你就不得不作兼容,除非這些人不是你的目標用戶。github

2.2 移動端爲何要作適配

在移動端雖然總體來講大部分瀏覽器內核都是webkit,並且大部分都支持CSS3的全部語法。可是,因爲手機屏幕尺寸不同,分辨率不同,或者你須要考慮橫豎屏的問題,這時候你也就不得不解決在不一樣手機上,不一樣狀況下的展現效果了。web

另一點,UI通常輸出的視覺稿只有一份,好比淘寶就會輸出:750px 寬度的(高度是動態的通常不考慮)(詳情),這時候開發人員就不得不針對這一份設計稿,讓其在不一樣屏幕寬度下顯示 一致瀏覽器

一致是什麼意思?就是下面提到的幾個主要解決的問題。sass

3、頁面適配主要解決的問題

  1. 元素自適應問題
  2. 文字rem問題
  3. 高清圖問題
  4. 1像素問題
  5. 橫豎屏顯示問題
  6. 手機字體縮放問題

3.1 元素自適應問題

舉個栗子:app

1080px 的視覺稿中,左上角有個logo,寬度是 180px(高度問題同理可得)。

那麼logo在不一樣的手機屏幕上等比例顯示應該多大尺寸呢?

其實按照比例換算,咱們大體能夠獲得以下的結果:

  • 在CSS像素是 375px 的手機上,應該顯示多大呢?結果是:375px * 180 / 1080 = 62.5px
  • 在CSS像素是 360px 的手機上,應該顯示多大呢?結果是:360px * 180 / 1080 = 60px
  • 在CSS像素是 320px 的手機上,應該顯示多大呢?結果是:320px * 180 / 1080 = 53.3333px

如下就是一些實現思路:

方案1:使用css的媒體查詢 @media

@media only screen and (min-width: 375px) {
  .logo {
    width : 62.5px;
  }
}

@media only screen and (min-width: 360px) {
  .logo {
    width : 60px;
  }
}

@media only screen and (min-width: 320px) {
  .logo {
    width : 53.3333px;
  }
}
複製代碼

這個方案有2個比較突出的問題:

  1. 若是再多一種屏幕尺寸,就得多寫一個 @media 查詢塊;
  2. 頁面上全部的元素都得在不一樣的 @media 中定義一遍不一樣的尺寸,這個代價有點高。

方案2:使用 rem 單位

注意咱們的推導公式:

  • 在CSS像素是 375px 的手機上,應該顯示多大呢?結果是:375px * 180 / 1080 = 62.5px
  • 在CSS像素是 360px 的手機上,應該顯示多大呢?結果是:360px * 180 / 1080 = 60px
  • 在CSS像素是 320px 的手機上,應該顯示多大呢?結果是:320px * 180 / 1080 = 53.3333px
@media only screen and (min-width: 375px) {
  html {
    font-size : 375px;
  }
}

@media only screen and (min-width: 360px) {
  html {
    font-size : 360px;
  }
}

@media only screen and (min-width: 320px) {
  html {
    font-size : 320px;
  }
}

.logo{
	width : 180rem / 1080;
}
複製代碼

方案2有效的解決了方案1中,同一個元素須要在多個 media 中寫的問題,這裏只須要多定義幾個 media 就能夠大體解決問題了。

可是本方案仍然有如下問題:

  1. 針對不一樣的手機分辨率,須要寫多套 @media 查詢語句,多一種機型就須要多寫一套查詢語句,並且隨着如今手機的層出不窮,這個頁面頗有可能在一些新出的機型上有問題。
  2. 每一個元素都須要除以1080這個設計稿的尺寸。

針對除以1080咱們能不能直接放到html的font-size上,變成這樣:

@media only screen and (min-width: 375px) {
  html {
    font-size : 375px / 1080;
  }
}

@media only screen and (min-width: 360px) {
  html {
    font-size : 360px / 1080;
  }
}

@media only screen and (min-width: 320px) {
  html {
    font-size : 320px / 1080;
  }
}

.logo{
	width : 180rem;
}
複製代碼

若是變成這樣,那麼 .logo 的css中就只須要按設計稿的尺寸大小寫就能夠了。到底可不能夠呢?

答案是:不能夠

主要緣由是,瀏覽器有最小字體限制:

  • PC上最小 font-size=12
  • 手機上最小 font-size=8

若是小於最小字體,那麼字體默認就是最小字體。

再來看上面的css,好比:

@media only screen and (min-width: 375px) {
  html {
    font-size : 375px / 1080; //0.347222px
  }
}

.logo{
	width : 180rem; //指望結果:375px / 1080 * 180 = 62.5px
}
複製代碼

因此當你這麼設置font-size時,在手機上因爲小於最小字體8px,因此頁面會按照默認字體算。

因此,最終就至關於你是這麼設置的:

@media only screen and (min-width: 375px) {
  html {
    font-size : 8px;
  }
}

.logo{
	width : 180rem; //實際結果:1440px
}
複製代碼

因此,你們在設置html的font-size的時候必定要保證最小等於8px!

於是爲了解決這個問題,建議你們使用Sass這種Css開發語言,能夠定義公式的,這樣寫css就方便了。

最終使用Sass的代碼以下:

@media only screen and (min-width: 375px) {
  html {
    font-size : 375px;
  }
}

@media only screen and (min-width: 360px) {
  html {
    font-size : 360px;
  }
}

@media only screen and (min-width: 320px) {
  html {
    font-size : 320px;
  }
}

//定義方法:calc
@function calc($val){
    @return $val / 1080;
}

.logo{
	width : calc(180rem);
}
複製代碼

以上方案雖然解決了問題,但任然有如下缺陷:

  1. 不一樣的尺寸須要寫多個 @media
  2. 依賴css的開發工具,好比:sass/less等
  3. 全部涉及到使用rem的地方,所有都須要調用方法 calc() ,這個也挺麻煩的。

方案3:js動態設置根字體

因爲方案2最主要的問題就是須要針對不一樣的屏幕尺寸,定義多個 @media,因此咱們先將這個字體設置改成動態設置。

注意咱們的推導公式:

  • 在CSS像素是 375px 的手機上,應該顯示多大呢?結果是:375px * 180 / 1080 = 62.5px
  • 在CSS像素是 360px 的手機上,應該顯示多大呢?結果是:360px * 180 / 1080 = 60px
  • 在CSS像素是 320px 的手機上,應該顯示多大呢?結果是:320px * 180 / 1080 = 53.3333px
//獲取手機屏幕寬度
var deviceWidth = document.documentElement.clientWidth;

//將方案二中的media中的設置,在這裏動態設置
//這裏設置的就是html的font-size
document.documentElement.style.fontSize = deviceWidth + 'px';
複製代碼

須要注意

document.documentElement.clientWidth 這個語句能獲取到的準確的手機尺寸的前提是創建在html中設置了以下標籤:

<meta name="viewport" content="width=device-width">
複製代碼

要否則獲取到的結果將始終是:980(查看緣由

而後Sass中就能夠按照設計稿的尺寸大小去寫就好了:

//定義方法:calc
@function calc($val){
    @return $val / 1080;
}

.logo{
	width : calc(180rem);
}
複製代碼

若是不考慮別的因素,只是頁面元素大致適配的話,該方案基本就知足要求了,可是現實中咱們其實還有不少問題,因此咱們的方案還須要繼續優化。

3.2 文字rem問題

文字也採用rem的單位主要有什麼問題呢?

  1. 可能會出現經過rem計算,最終呈現到頁面上是 23.335px 這樣的奇葩的字體大小,可能還會所以出現鋸齒、模糊不清等問題;
  2. 對於大屏但願一行顯示的文字多一些,小屏顯示的少一些,而不是一視同仁的所有顯示一樣多的文字。這樣在大屏下顯得文字特別大(下文 3.5 橫豎屏顯示問題 會仔細講)。

對於以上問題,我我的的建議

  1. 對於出現奇葩字體的問題,其實手機上表現並沒那麼明顯,主要緣由是如今屏幕顯示效果統一編號,另外html對字體顯示也作優化,因此,若是產品要求不嚴格,能夠不用考慮處理;
  2. 對於橫豎屏問題,看狀況吧,若是要求不嚴格,也能夠不用考慮。

若是必定要解決這個問題,那麼字體就不要使用rem方案了,而是繼續使用px單位。

咱們上面提到 大屏 小屏 其實隱含的意思並非手機屏幕大,而是手機的屏幕分辨率不同,其實就是dpr不同,因此咱們針對不一樣的dpr設置具體的字體就能夠了。

好比,咱們針對頁面的標題的字體大小就能夠以下設置:

.title {
    font-size: 12px;
}
[data-dpr="2"] .title {
    font-size: 24px;
}
[data-dpr="3"] .title {
    font-size: 36px;
}
複製代碼

3.3 高清圖問題

先來看看 這裏 這篇文章,有講解了爲何在有些屏幕上要使用 @2x @3x 的高清圖。

再來看看 這裏 講解了具體的高清圖的解決方案。

我這裏簡單概括下。

3.3.1 對於 <img> 標籤引入的圖片高清解決方案

一、使用 srcset 標籤

<img src="http://g.ald.alicdn.com/bao/uploaded/i1/TB1d6QqGpXXXXbKXXXXXXXXXXXX_!!0-item_pic.jpg_160x160q90.jpg" srcset="http://img01.taobaocdn.com/imgextra/i1/803091114/TB2XhAPaVXXXXXmXXXXXXXXXXXX_!!803091114.jpg 2x, http://gtms04.alicdn.com/tps/i4/TB1wDjWGXXXXXbtXVXX6Cwu2XXX-398-510.jpg_q75.jpg 3x">
複製代碼

關於 srcset 的說明:猛戳這裏

二、使用js自帶的 Image 異步加載圖片

<img id="img" data-src1x="xxx@1x.jpg" data-src2x="xxx@2x.jpg" data-src3x="xxx@3x.jpg"/>
複製代碼
var dpr = window.devicePixelRatio;
if(dpr > 3){
	dpr = 3;
};

var imgSrc = $('#img').data('src'+dpr+'x');
var img = new Image();
img.src = imgSrc;
img.onload = function(imgObj){
	$('#img').remove().prepend(imgObj);//替換img對象
};

複製代碼

3.3.2 對於背景圖片高清解決方案

一、使用 media query 來處理

/* 普通顯示屏(設備像素比例小於等於1)使用1倍的圖 */
.css{
    background-image: url(img_1x.png);
}

/* 高清顯示屏(設備像素比例大於等於2)使用2倍圖 */
@media only screen and (-webkit-min-device-pixel-ratio:2){
    .css{
        background-image: url(img_2x.png);
    }
}

/* 高清顯示屏(設備像素比例大於等於3)使用3倍圖 */
@media only screen and (-webkit-min-device-pixel-ratio:3){
    .css{
        background-image: url(img_3x.png);
    }
}
複製代碼

二、使用 image-set 來處理(有兼容問題)

.css {
    background-image: url(1x.png); /*不支持image-set的狀況下顯示*/
    background: -webkit-image-set(
            url(1x.png) 1x,/* 支持image-set的瀏覽器的[普通屏幕]下 */
            url(2x.png) 2x,/* 支持image-set的瀏覽器的[2倍Retina屏幕] */
            url(3x.png) 3x/* 支持image-set的瀏覽器的[3倍Retina屏幕] */
    );
}

複製代碼

3.4 1像素問題

什麼是 1像素問題 ?

咱們說的1像素,就是指1 CSS像素。

好比設計師畫了一條線,可是在有些手機上看着明顯很粗,爲何?

由於這個1px,在有些設備上(好比:dpr=3),就是用了橫豎都是3的物理像素矩陣(即:3x3=9 CSS像素)來顯示這1px,致使在這些設備上,這條線看上去很是粗!

其實在在中手機上應該是1/3px顯示這條線。

關於 dpr,不理解的,能夠看看以前的 這篇 文章。

問題描述清楚了,咱們該怎麼處理呢?

方案1:使用css3的 scaleY(0.5) 來解決

好比:div的border-top的1px問題解決。

.div:before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: auto;
  right: auto;
  height: 1px;
  width: 100%;
  background-color: #c8c7cc;
  display: block;
  z-index: 15;
  -webkit-transform-origin: 50% 0%;
          transform-origin: 50% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
  .div:before {
    -webkit-transform: scaleY(0.5);
            transform: scaleY(0.5);
  }
}
@media only screen and (-webkit-min-device-pixel-ratio: 3) {
  .div:before {
    -webkit-transform: scaleY(0.33);
            transform: scaleY(0.33);
  }
}
複製代碼

可是,這種方案只能解決直線的問題,涉及到圓角之類的,就無能爲力!

方案2:頁面縮放解決問題

咱們先來說講頁面縮放能解決1px問題的原理示。

首先你們須要瞭解一些 viewport 的常識,參考:這裏

假如如下手機的 dpr=2

對於dpr=2的手機設備,1px就會有 2x2 的物理像素來渲染,可是當縮放之後其實就變成 1x1 個單位渲染了,看下面示意圖:

因此,咱們的思路就是將真個頁面縮小dpr倍,再將頁面的根字體放大dpr倍。這樣頁面雖然變小了,可是因爲頁面總體採用rem單位,當根字體放大dpr倍之後,總體都放大了,看上去總體樣式沒什麼變化。

一、將scale設置爲1/dpr

假如:dpr = 2

<meta name="viewport" content="width=device-width,initial-scale=0.5">
複製代碼

二、clientWidth獲取的值會自動擴大dpr倍

好比,之前是360px,當頁面縮小0.5倍,獲取到的值會變爲720px。

不知道這個原理的,這篇文章講的仍是比較清楚:這裏

var deviceWidth = document.documentElement.clientWidth;
document.documentElement.style.fontSize = deviceWidth + 'px';
複製代碼

三、css中涉及到1像素問題的地方使用 px 做爲單位

好比:

.box{
	border : 1px solid #ddd;
}
複製代碼

以上步驟最終整理的結果:

html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
</head>
<body>
    <div class="box">
        <div class="logo">Logo</div>
    </div>
</body>
</html>
複製代碼

js:

//獲取屏幕寬度、dpr值
var deviceWidth = document.documentElement.clientWidth,
    dpr = window.devicePixelRatio || 1;

//設置根字體擴大dpr倍
//因爲deviceWidth當頁面縮小dpr倍時,自己獲取的值就增長dpr倍
//因此這裏不須要再乘以dpr了
document.documentElement.style.fontSize = deviceWidth + 'px';

//設置頁面縮放dpr倍
document.getElementsByName('viewport')[0]
    .setAttribute('content','width=device-width;initial-scale=' + 1/dpr)
複製代碼

scss:

@function calc($val){
    @return $val / 1080;
}

.logo{
	width : calc(180rem);
}

.box{
	border : 1px solid #ddd;
}
複製代碼

3.5 橫豎屏顯示問題

橫豎屏問題,就是當你橫屏手機、豎屏手機時看到的不同的效果問題。

我這裏要說的這個問題,就是設計師會針對橫屏或者豎屏,作不同的設計,好比:橫屏時顯示摘要,豎屏時只有標題,這種狀況下,咱們應該怎麼適配的問題。

關於橫豎屏問題,我將會分2個部分來講明:

  1. 橫豎屏顯示內容不一樣;
  2. 橫豎屏顯示樣式不一樣;

3.5.1 橫豎屏顯示內容問題

咱們知道橫屏,至關於屏幕變寬了,這時候一行顯示的內容就能夠更多。因此,設計師可能會對橫豎屏作2種不一樣的內容設計,如:

若是設計師自己就設計了2套樣式,那麼咱們只須要準備2套css,依據橫豎屏直接顯示對應的樣式,而後html中作好兼容便可。

下文會將如何判斷橫豎屏。

3.5.2 橫豎屏顯示樣式問題

這裏有個要說的就是,設計師沒有設計橫屏的樣式,那麼若是咱們按照上文提到的方案去處理,那麼就會發如今橫屏模式下字體顯得很是大(由於屏幕寬了),顯示的內容就少了。

這種狀況會顯得很不協調,雖然仍是等比例顯示的,只不過須要多拖動下滾動條而已,可是你會以爲很怪。尤爲是再有彈出框的時候,會更麻煩,彈出框有時候可能還會顯示不徹底。。。

好比,下面的樣式:

像這種問題,咱們上面提到的依據屏幕寬度自動調整根目錄font-size的大小,就有點不合適了。這樣雖然保證了橫向的比例是嚴格按照設計搞來的,可是顯示上很是醜。

因此,咱們通常的作法就是在橫屏的時候將 deviceWidth=deviceHeight

  • 正常豎屏大小:
  • 橫屏時讓width=height
  • 不作橫豎屏特殊寬度處理時

以上3組畫面對比咱們獲得的效果是:

  1. 在橫屏下若是讓width=height,那麼總體頁面的寬度等於豎屏時看到的寬度,總體佈局不會有變化,只是縱向看到的內容多少發生了變化;
  2. 若是橫屏不作處理,橫屏是width其實就等於豎屏時的height,即700px,這時候總體頁面顯示很是寬,文字比較大。

因此,通過咱們的實際對比體驗之後,一致認爲橫屏時讓 width=height 體驗比較好。

附上核心代碼:

var deviceWidth = document.documentElement.clientWidth,
    deviceHeight = document.documentElement.clientHeight

//橫屏狀態
if (window.orientation === 90 || window.orientation === -90) {
    deviceWidth = deviceHeight;
};

//設置根字體大小
document.documentElement.style.fontSize = deviceWidth + 'px';
複製代碼

3.5.3 附1:JS檢測橫豎屏

js獲取屏幕旋轉方向:window.orientation

  • 0 - 正常方向
  • -90 - 屏幕順時鐘旋轉90度
  • 90 - 屏幕逆時針旋轉90度
  • 180 - 屏幕旋轉180度
window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function() {
    if (window.orientation === 180 || window.orientation === 0) { 
        console.log('豎屏狀態!');
    };
    if (window.orientation === 90 || window.orientation === -90 ){ 
        console.log('橫屏狀態!');
    }  
}, false); 
複製代碼

3.5.4 附2:CSS判斷橫豎屏

  • 寫在同一個CSS中:
@media screen and (orientation: portrait) {
  /*豎屏 css*/
} 
@media screen and (orientation: landscape) {
  /*橫屏 css*/
}
複製代碼
  • 分開寫在2個CSS中,在link中經過media篩選加載:
<!-- 豎屏 -->
<link rel="stylesheet" media="all and (orientation:portrait)" href="portrait.css">

<!-- 豎屏 -->
<link rel="stylesheet" media="all and (orientation:landscape)" href="landscape.css">

複製代碼

3.6 手機字體縮放問題

手機字體縮放是什麼問題呢?

就是當你在手機 設置 -> 字體設置 中將字體放大或者縮小,使得手機總體系統字體發生了變化,這時候可能就會影響到H5頁面正常的顯示。

通過實際測試,這個問題當前發生的機率不是很大,由於不少手機廠商都已經作了保護措施。可是爲了保險起見,咱們仍是有必要進行檢測,一旦不同就要採起措施。

3.6.1 如何檢測手機字體不是默認字體

var deviceWidth = document.documentElement.clientWidth;

//設置根字體大小
var setFz = deviceWidth + 'px';
document.documentElement.style.fontSize = setFz;

//獲取實際html字體大小
var realFz = window.getComputedStyle(document.documentElement)
	.getPropertyValue('font-size') //如:360px

//比較兩者是否相同
if(setFz !== realFz){
    //TODO 設置的字體和實際顯示的字體不一樣
};
複製代碼

3.6.2 若是手機字體不是默認字體如何處理

好比:你想設置的字體大小爲100px,可是實際大小卻爲50px,那麼你能夠肯定其實用戶字體是縮放了0.5,這時候你就須要將你的字體擴大1倍,這樣才能保證明際頁面的字體是100。

因此,按照這個等比例換算之後,咱們就須要從新設置頁頁面的font-size。

var deviceWidth = document.documentElement.clientWidth;

//設置根字體大小
var setFz = deviceWidth + 'px';
document.documentElement.style.fontSize = setFz;

//獲取實際html字體大小
var realFz = window.getComputedStyle(document.documentElement)
	.getPropertyValue('font-size') //如:360px

//比較兩者是否相同
if(setFz !== realFz){
    //去掉單位px,下面要參與計算
    setFz = parseFloat(setFz);
    realFz = parseFloat(realFz);
    
    //從新計算要設置的新的字體大小
    //公式推導:100 -> 50,x -> 100,求x?
    //即:setFz -> realFz, x -> setFz,求x?
    var x =  setFz * setFz / realFz;
    
    //從新設置html的font-size
    document.documentElement.style.fontSize = x + 'px';
};
複製代碼

這麼作理論上已經解決了問題,可是還有點瑕疵,問題就是:

  • 若是字體不是默認字體,首先會設置一次font-size,從新計算後再次設置一次font-size,反應到頁面上就是頁面可能會快速晃動一次,由於兩次設置的字體大小不同,若是手機配置不高,估計晃動會很明顯。

如何解決這個問題?思路就是:

  1. 給頁面增長一個隱藏元素,設置其字體大小爲100px
  2. 獲取這個元素在頁面上的實際字體大小是否爲100px
  3. 若是設置的和實際的不等,則計算其比例。

最終代碼片斷以下:

var deviceWidth = document.documentElement.clientWidth;

var setFz = '100px';

//給head增長一個隱藏元素
var h = document.getElementsByTagName('head')[0],
    s = document.createElement('span');
    s.style.fontSize = setFz;
    s.style.display = 'none';
    h.appendChild(s);

//判斷元素真實的字體大小是否100px
//若是不相等則獲取真實的字體換算比例
var realFz = getComputedStyle(s).getPropertyValue('font-size');

if(setFz !== 'realFz'){
    //去掉單位px,下面要參與計算
    setFz = parseFloat(setFz);
    realFz = parseFloat(realFz);
    
    //因爲:var x = setFz * setFz / realFz;
    //公式推導:x -> setFz, y -> deviceWidth
    //因此:var y = deviceWidth * x / setFz;
    
    //重置deviceWidth
    deviceWidth = deviceWidth * setFz / realFz;
};

document.documentElement.style.fontSize = deviceWidth + 'px';
複製代碼

4、最終適配方案(v1.0)

除了上面一步步的分析中間的原理以外,咱們可能還須要考慮或者遇到如下問題:

  1. 到底何時動態初始化上面的js腳本?
  2. 偶爾還可能會遇到進入頁面時 document.documentElement.clientWidth=0 的bug?
  3. 頁面晃動?頁面空白?頁面總體凌亂而後又正常等問題?

因此,在儘量的解決諸多問題後,最終的腳本以下:

html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
</head>
<body>
    <!-- 正文 -->
</body>
</html>
複製代碼

js:

/** * @DESCRIPTION 移動端頁面適配解決方案 v1.0 * @AUTHOR Night * @DATE 2018年08月01日 */
(function(window, document){
    var docEle = document.documentElement,
        dpr    = window.devicePixelRatio || 1,
        scale  = 1 / dpr;
    
    var fontSizeRadio = 1, //手機字體正常比例
        isLandscape   = false;//是否橫屏
    
    ///////////////////////// viewport start //////////////////////////////////
    
    //設置頁面縮放比例並禁止用戶手動縮放
    document.getElementsByName('viewport')[0].setAttribute('content','width=device-width,initial-scale='+scale+',maximum-scale='+scale+',minimum-scale='+scale+',user-scalable=no');
    
	///////////////////////// viewport end //////////////////////////////////
    
    //橫屏狀態檢測
    if (window.orientation === 90 || window.orientation === -90) {
        isLandscape = true;
    };

    ///////////////////// system font-size check start //////////////////////
    
    //試探字體大小,用於檢測系統字體是否正常
    var setFz = '100px';

    //給head增長一個隱藏元素
    var headEle = document.getElementsByTagName('head')[0],
        spanEle = document.createElement('span');
        spanEle.style.fontSize = setFz;
        spanEle.style.display = 'none';
        headEle.appendChild(spanEle);

    //判斷元素真實的字體大小是否setFz
    //若是不相等則獲取真實的字體換算比例
    var realFz = getComputedStyle(headEle).getPropertyValue('font-size');

    if(setFz !== 'realFz'){
        //去掉單位px,下面要參與計算
        setFz = parseFloat(setFz);
        realFz = parseFloat(realFz);

        //獲取字體換算比例
        fontSizeRadio = setFz / realFz;
    };
    
    ///////////////////// system font-size check end //////////////////////
    
    var setBaseFontSize = function(){
        var deviceWidth = docEle.clientWidth,
            deviceHeight= docEle.clientHeight;
        
        if(isLandscape){
            deviceWidth = deviceHeight;
        };
        
        docEle.style.fontSize = deviceWidth * fontSizeRadio + 'px';
    };
    setBaseFontSize();
    
    //頁面發生變化時重置font-size
    //防止多個事件重複執行,增長延遲300ms操做(防抖)
    var tid;
    window.addEventListener('resize', function() {
        clearTimeout(tid);
        tid = setTimeout(setBaseFontSize, 300);
    }, false);
    window.addEventListener('pageshow', function(e) {
        if (e.persisted) {
            clearTimeout(tid);
            tid = setTimeout(setBaseFontSize, 300);
        };
    }, false);
    
})(window, document);
複製代碼

scss:

//設計稿尺寸大小,假如設計稿寬度750
$baseDesignWidth = 750;

@function calc($val){
    @return $val / $baseDesignWidth;
}

//適配元素採用rem,假如設計稿中元素寬度180
.logo{
	width : calc(180rem);
}

//邊框採用px,假如設計稿邊框寬度1px
.box{
	border : 1px solid #ddd;
}
複製代碼

5、新頁面適配技術能夠考慮(v2.0)

若是不太考慮老的手機型號,能夠採用 viewport 單位。

因爲我本人也沒有在項目中使用這個方案,因此不過多發表言論,你們有興趣的能夠研究下。

具體方案細節參考:

6、後記

講了這麼多,這裏總結下,任何事情弄懂原理最重要!

好比,當你首次看 使用Flexible實現手淘H5頁面的終端適配 這篇文章的時候你會很感慨,感受頗有收穫,可是當你實際開始項目的時候,殊不知道該怎麼下手。

俗話說,臺上一分鐘,臺下十年功。

爲了寫本文以及姊妹篇,我我的零零散散的時間加起來不下1個月,一直到(2016年12月2日)才發表了本文的初版。因爲收到一些流言反饋和後續知識的積累,因而決定今天(2018年08月01日)再把它從新整理一遍,以讓你們更清楚這中間的原理。

由於中間涉及的東西太多,只要有一個知識有些不清楚,可能就會卡克!好比這個概念 dips,不一樣的文章有不一樣的說法,並且還給你解釋了它跟 dip 的不一樣,其實就是指 CSS像素,這些人故意發明一些專業詞彙,搞的你暈頭轉向,因此,當你看了個人這兩篇文章,也許仍是隻知其一;不知其二,這很正常,慢慢來,多多練習,相信你會明白的。

若是還有哪裏不清楚,或者本文有錯誤的地方,感謝批評指正。

本文從新編輯於:2018年08月01日

  1. 針對你們的留言以及我的的反覆推敲,從新整理了這遍文章;
  2. 增長針對手機自己字體放大、縮小的解決方案,以及一些新的替代方案思路。

參考

(全文完)

相關文章
相關標籤/搜索