前端適配方案

在進(jìn)入正文之前,我們需要先了解一些viewport相關(guān)的概念。

viewport

一般來(lái)說(shuō),我們?cè)诖a的最開(kāi)始會(huì)寫(xiě)上這么一句

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

移動(dòng)端瀏覽器可以在一個(gè)比屏幕更寬的虛擬”窗口“中渲染頁(yè)面,從而無(wú)需將所有頁(yè)面都?jí)嚎s進(jìn)小屏幕里(那樣會(huì)把很多沒(méi)有針對(duì)移動(dòng)端進(jìn)行優(yōu)化的站點(diǎn)打亂)。用戶(hù)可以通過(guò)平移和縮放來(lái)瀏覽頁(yè)面的不同區(qū)域。比如我們把一個(gè)頁(yè)面的寬度寫(xiě)成了10000px,那么我們照樣可以通過(guò)平移縮放來(lái)看到這個(gè)頁(yè)面,當(dāng)然這是不可取的,所以我們就需要以上代碼,將viewport的width設(shè)置為設(shè)備的寬度,縮放的倍數(shù)是1,且不讓用戶(hù)進(jìn)行縮放(這個(gè)可以根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景來(lái)設(shè)置)。經(jīng)過(guò)以上設(shè)置,我們就可以開(kāi)始進(jìn)入愉快寫(xiě)代碼的第一步了~

  • 物理像素DP(device pixels)和css像素

物理像素一般在設(shè)備出廠的時(shí)候就被設(shè)置好了,也叫設(shè)備像素,單 位是pt(point),pt是一個(gè)物理單位,指的是組成顯示器屏幕的絕對(duì)長(zhǎng)度。我們買(mǎi)電視機(jī)的時(shí)候,會(huì)說(shuō),我買(mǎi)個(gè)70寸的電視機(jī)。

1英寸=72pt

px(pixel)是一個(gè)虛擬的單位,也是一個(gè)相對(duì)的單位。根據(jù)《CSS權(quán)威指南》的像素理論中的解釋?zhuān)?/p>

顯示器上的小色框是像素
CSS2.1 建議采用96ppi(pixels per inch),這是Windows機(jī)器常用的度量。Mac系統(tǒng)下用的是72ppi。

摘錄來(lái)自: Eric Meyer. “CSS權(quán)威指南第三版”。 iBooks.

1px=1/ppi英寸

通過(guò)inch就可以連接器pt和px的關(guān)系。


mac網(wǎng)頁(yè)的例子
  • 設(shè)備獨(dú)立像素DIP(Device independent Pixel)

設(shè)備獨(dú)立像素,也稱(chēng)為邏輯像素,也叫css像素。我們可以通過(guò)screen.width或者screen.height輸出。比如iPhone的css像素就是375px*667px,iPhone 6 則采用了750×1334分辨率的屏幕,PPI值為326。

iphone6示例圖

物理像素和css像素的計(jì)算公式是:

DPR = 物理像素/CSS像素

css reset樣式重置

為什么要進(jìn)行css reset操作?

css reset主要是因?yàn)閔tml標(biāo)簽在瀏覽器中都有各自的默認(rèn)樣式。

比如: p 標(biāo)簽有上下邊距,strong標(biāo)簽有字體加粗樣式,em標(biāo)簽有字體傾斜樣式。不同瀏覽器的默認(rèn)樣式之間也會(huì)有差別,例如ul默認(rèn)帶有縮進(jìn)的樣式,在IE 下,它的縮進(jìn)是通過(guò)margin實(shí)現(xiàn)的,而Firefox下,它的縮進(jìn)是由padding實(shí)現(xiàn)的。在切換頁(yè)面的時(shí)候,瀏覽器的默認(rèn)樣式往往會(huì)給我們帶來(lái)麻煩,影響開(kāi)發(fā)效率。所以解決的方法就是一開(kāi)始就將瀏覽器的默認(rèn)樣式全部去掉,更準(zhǔn)確說(shuō)就是通過(guò)重新定義標(biāo)簽樣式。

常用的適配方案

  • flex
<div class="content">
     <div class="con">
         <div class="a"></div>
     </div>
     <div class="con">
         <div class="a"></div>
     </div>
     <div class="con">
         <div class="a"></div>
     </div>
</div>

    .content{
         display: flex;
    }
    .con{
         display: flex;
         justify-content:center;
         align-items:center;
         flex:1;
         height: 300px;
         background: #999;
         color:#fff;
         border:1px solid #000;
    }
    .a{
         width: 30px;
         height: 30px;
         background: #f00;
    }
demo

demo地址

  • 媒體查詢(xún)media query

    一個(gè)媒體查詢(xún)由一個(gè)可選的媒體類(lèi)型和零個(gè)或多個(gè)使用媒體功能的限制了樣式表范圍的表達(dá)式組成,例如寬度、高度和顏色。媒體查詢(xún),添加自CSS3,允許內(nèi)容的呈現(xiàn)針對(duì)一個(gè)特定范圍的輸出設(shè)備而進(jìn)行裁剪,而不必改變內(nèi)容本身。

    我們把上面flex的css換掉其中a的樣式,來(lái)看一下media query的作用。

    .a{
     background:#f00;
    }
    @media (max-width: 800px) {
     .a {
     width:50px;
     height:50px;
     font-size:12px;
     color:#2e9900;
     }
    }
    @media (min-width:801px) and (max-width:1000px) {
     .a {
     width:200px;
     height:200px;
     font-size:20px;
     color:blue;
     }
    }
    @media (min-width: 1001px) {
     .a {
     width:450px;
     height:450px;
     font-size:40px;
     }
    }

media query demo

  • transform-scale

其實(shí)我自己覺(jué)得transform-scale是一個(gè)不錯(cuò)的適配方式,簡(jiǎn)單明了,而且暫時(shí)也沒(méi)有遇到過(guò)什么適配方面的大坑,相對(duì)而言還比較精確。

處理方式很簡(jiǎn)單,樣式完全按照設(shè)計(jì)稿的px來(lái)寫(xiě)。然后在js中計(jì)算當(dāng)前頁(yè)面的寬度與設(shè)計(jì)稿的寬度的比,直接對(duì)body進(jìn)行transform-scale的縮放。

如果非要說(shuō)有什么問(wèn)題的話,那就是如果需要考慮橫屏受眾,那就得針對(duì)一些橫屏的狀態(tài)做一些特殊處理。還有就是transform-scale縮小沒(méi)有問(wèn)題,放大的話,會(huì)導(dǎo)致頁(yè)面模糊。

這個(gè)方案就看自己業(yè)務(wù)需求來(lái)選擇了。

  • rem

rem算是一個(gè)使用很廣泛的適配方案了。

實(shí)現(xiàn)的方式就是給html根節(jié)點(diǎn)設(shè)置一個(gè)font-size,作為頁(yè)面計(jì)算的基準(zhǔn)。一般這個(gè)基準(zhǔn)會(huì)根據(jù)設(shè)計(jì)稿來(lái)定。

假設(shè)設(shè)計(jì)稿的寬度是750px,那最初我們可以將font-size設(shè)為75px,頁(yè)面寬度就是10rem。

然后在頁(yè)面中用js動(dòng)態(tài)獲取一下當(dāng)前頁(yè)面寬度,計(jì)算出頁(yè)面寬度與750px的比例,獲取當(dāng)前頁(yè)面根節(jié)點(diǎn)上應(yīng)該帶上多大的font-size,假設(shè)當(dāng)前頁(yè)面寬度是375px,那么根節(jié)點(diǎn)上帶上的font-size應(yīng)該是37.5px。

這個(gè)方案是一個(gè)與dpr無(wú)關(guān)的方案,就是說(shuō)完全依賴(lài)的是設(shè)備獨(dú)立像素而不是設(shè)備的物理像素,這樣就會(huì)存在一個(gè)問(wèn)題,在dpr較大的高清屏上,可能導(dǎo)致模糊。

當(dāng)然,我們也是可以加上dpr來(lái)計(jì)算根節(jié)點(diǎn)的font-size的。

  • flexible.js

flexible是手淘的一套解決方案,這是一套dpr相關(guān)的解決方案。

實(shí)現(xiàn)的原理是:

flexible將頁(yè)面分成100份,即100a,10a=1rem。比如,頁(yè)面寬度為750px,那么一份為75px,1rem=75px。

通過(guò)js動(dòng)態(tài)獲取當(dāng)前頁(yè)面的dpr和設(shè)備獨(dú)立像素。拿iPhone 8 plus舉例,得到dpr是3,設(shè)備獨(dú)立像素是414px。那么html上寫(xiě)的font-size的大小是這么計(jì)算的:

dpr * 414 / 10

最終得到的font-size值是124.2px,然后在meta的initial-scale里會(huì)根據(jù)dpr再進(jìn)行一下頁(yè)面縮放,這就可以保證頁(yè)面的精細(xì)程度。

但是如果在meta viewport中手動(dòng)設(shè)置了initial-scale,那么不管js獲取到的dpr是多少,都會(huì)強(qiáng)制認(rèn)為dpr是手動(dòng)設(shè)置的值;

手淘處理文字的方式,并沒(méi)有采用rem,因?yàn)閞em計(jì)算出的小數(shù),在對(duì)小數(shù)敏感度不一樣的機(jī)型上會(huì)導(dǎo)致展示誤差,且小于12px的文字并不會(huì)正常被渲染。也會(huì)導(dǎo)致一些line-height的問(wèn)題。

  • vm

隨著前端技術(shù)的演進(jìn),vw這個(gè)單位又走上了歷史的舞臺(tái)。

CSS Values and Units Module Level 3中和Viewport相關(guān)的單位有四個(gè),分別為vwvh、vminvmax。

-   `vw`:是Viewport's width的簡(jiǎn)寫(xiě),`1vw`等于`window.innerWidth`的`1%`

-   `vh`:和`vw`類(lèi)似,是Viewport's height的簡(jiǎn)寫(xiě),`1vh`等于`window.innerHeihgt`的`1%`

-   `vmin`:`vmin`的值是當(dāng)前`vw`和`vh`中較小的值

-   `vmax`:`vmax`的值是當(dāng)前`vw`和`vh`中較大的值

常見(jiàn)的屏幕適配問(wèn)題和解決方案

  • line-height
    一般客戶(hù)端的webview會(huì)有一個(gè)默認(rèn)的line-height,大概會(huì)是在22px的樣子。我們有可能會(huì)遇到一個(gè)問(wèn)題就是,在我們?cè)O(shè)置好一個(gè)line-height之后,但是渲染出來(lái)的文字相對(duì)于我們預(yù)想的是偏上的。導(dǎo)致這個(gè)問(wèn)題的原因是,我們?cè)O(shè)置的line-height是小于webview預(yù)設(shè)的最小line-height的,這樣我們?cè)O(shè)置的那個(gè)值會(huì)被忽略。
    解決的方案是:
    盡量保證font-size是大于12px的,將line-height設(shè)置為1,使用上下padding使文字居中。在一些必須需要font-size小于12px的地方,可以先放font-size大于12px,再用transform:scale去縮小。
    但是這一點(diǎn)從實(shí)際經(jīng)驗(yàn)來(lái)看,我更偏愛(ài)手淘的方案,根據(jù)dpr或者mediaquery設(shè)置一個(gè)固定的字體,這就需要和設(shè)計(jì)同學(xué)定下一個(gè)設(shè)計(jì)規(guī)范。
  • 中英文的字號(hào)一樣,但是實(shí)際高度卻不一樣
    文字的大小,取決于設(shè)計(jì)文字的人,就像我們前幾天遇到的英文比中文同字號(hào)小的問(wèn)題,如果光靠上下的padding來(lái)寫(xiě)的話,那就可能會(huì)出現(xiàn)純英文或者數(shù)字那塊會(huì)比較矮。
  • 1像素問(wèn)題
    產(chǎn)生原因:因?yàn)閐pr高的設(shè)備下,寫(xiě)的1像素,實(shí)際是比1的dpr倍。
    解決方案:1)如果整體縮放頁(yè)面的話,1像素的線也會(huì)被一起縮放
    2)可以將線條所在元素用transform-scale縮小
  • 如果設(shè)計(jì)師在設(shè)計(jì)稿上使用的文字很細(xì),比如華文細(xì)黑這樣的,那前端為了適配更完美,可以用一個(gè)樣式-webkit-font-smoothing: antialiased;
  • 在移動(dòng)端我們寫(xiě)了overflow:scroll;之后,滑動(dòng)可能并不能像我們預(yù)料中的那么順暢,可以使用樣式-webkit-overflow-scrolling: touch;
  • 如果input或button的有怪異的默認(rèn)樣式,嘗試appearance:none;(-webkit-appearance:none;)

參考文檔:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容