移動端適配,是咱們在開發中常常會遇到的,這裏面可能會遇到很是多的問題:css
1px
問題UI
圖完美適配方案iPhoneX
適配方案上面這些問題可能咱們在開發中已經知道如何解決,可是問題產生的原理,以及解決方案的原理可能會模糊不清。在解決這些問題的過程當中,咱們每每會遇到很是多的概念:像素、分辨率、PPI
、DPI
、DP
、DIP
、DPR
、視口等等,你真的能分清這些概念的意義嗎?html
本文將從移動端適配的基礎概念出發,探究移動端適配各類問題的解決方案和實現原理。react
通常用英寸描述屏幕的物理大小,如電腦顯示器的17
、22
,手機顯示器的4.8
、5.7
等使用的單位都是英寸。git
須要注意,上面的尺寸都是屏幕對角線的長度:github
英寸(inch
,縮寫爲in
)在荷蘭語中的本意是大拇指,一英寸就是指甲底部普通人拇指的寬度。web
英寸和釐米的換算:1英寸 = 2.54 釐米
chrome
像素即一個小方塊,它具備特定的位置和顏色。react-native
圖片、電子屏幕(手機、電腦)就是由無數個具備特定顏色和特定位置的小方塊拼接而成。瀏覽器
像素能夠做爲圖片或電子屏幕的最小組成單位。安全
下面咱們使用sketch
打開一張圖片:
將這些圖片放大便可看到這些像素點:
一般咱們所說的分辨率有兩種,屏幕分辨率和圖像分辨率。
屏幕分辨率指一個屏幕具體由多少個像素點組成。
下面是apple
的官網上對手機分辨率的描述:
iPhone XS Max
和 iPhone SE
的分辨率分別爲2688 x 1242
和1136 x 640
。這表示手機分別在垂直和水平上所具備的像素點數。
固然分辨率高不表明屏幕就清晰,屏幕的清晰程度還與尺寸有關。
咱們一般說的圖片分辨率
實際上是指圖片含有的像素數
,好比一張圖片的分辨率爲800 x 400
。這表示圖片分別在垂直和水平上所具備的像素點數爲800
和400
。
同一尺寸的圖片,分辨率越高,圖片越清晰。
PPI(Pixel Per Inch)
:每英寸包括的像素數。
PPI
能夠用於描述屏幕的清晰度以及一張圖片的質量。
使用PPI
描述圖片時,PPI
越高,圖片質量越高,使用PPI
描述屏幕時,PPI
越高,屏幕越清晰。
在上面描述手機分辨率的圖片中,咱們能夠看到:iPhone XS Max
和 iPhone SE
的PPI
分別爲458
和326
,這足以證實前者的屏幕更清晰。
因爲手機尺寸爲手機對角線的長度,咱們一般使用以下的方法計算PPI
:
iPhone 6
的PPI
爲
那它每英寸約含有326
個物理像素點。
DPI(Dot Per Inch)
:即每英寸包括的點數。
這裏的點是一個抽象的單位,它能夠是屏幕像素點、圖片像素點也能夠是打印機的墨點。
平時你可能會看到使用DPI
來描述圖片和屏幕,這時的DPI
應該和PPI
是等價的,DPI
最經常使用的是用於描述打印機,表示打印機每英寸能夠打印的點數。
一張圖片在屏幕上顯示時,它的像素點數是規則排列的,每一個像素點都有特定的位置和顏色。
當使用打印機進行打印時,打印機可能不會規則的將這些點打印出來,而是使用一個個打印點來呈現這張圖像,這些打印點之間會有必定的空隙,這就是DPI
所描述的:打印點的密度。
在上面的圖像中咱們能夠清晰的看到,打印機是如何使用墨點來打印一張圖像。
因此,打印機的DPI
越高,打印圖像的精細程度就越高,同時這也會消耗更多的墨點和時間。
實際上,上面咱們描述的像素都是物理像素
,即設備上真實的物理單元。
下面咱們來看看設備獨立像素
到底是如何產生的:
智能手機發展很是之快,在幾年以前,咱們還用着分辨率很是低的手機,好比下面左側的白色手機,它的分辨率是320x480
,咱們能夠在上面瀏覽正常的文字、圖片等等。
可是,隨着科技的發展,低分辨率的手機已經不能知足咱們的需求了。很快,更高分辨率的屏幕誕生了,好比下面的黑色手機,它的分辨率是640x940
,正好是白色手機的兩倍。
理論上來說,在白色手機上相同大小的圖片和文字,在黑色手機上會被縮放一倍,由於它的分辨率提升了一倍。這樣,豈不是後面出現更高分辨率的手機,頁面元素會變得愈來愈小嗎?
然而,事實並非這樣的,咱們如今使用的智能手機,無論分辨率多高,他們所展現的界面比例都是基本相似的。喬布斯在iPhone4
的發佈會上首次提出了Retina Display
(視網膜屏幕)的概念,它正是解決了上面的問題,這也使它成爲一款跨時代的手機。
在iPhone4
使用的視網膜屏幕中,把2x2
個像素當1
個像素使用,這樣讓屏幕看起來更精緻,可是元素的大小卻不會改變。
若是黑色手機使用了視網膜屏幕的技術,那麼顯示結果應該是下面的狀況,好比列表的寬度爲300
個像素,那麼在一條水平線上,白色手機會用300
個物理像素去渲染它,而黑色手機實際上會用600
個物理像素去渲染它。
咱們必須用一種單位來同時告訴不一樣分辨率的手機,它們在界面上顯示元素的大小是多少,這個單位就是設備獨立像素(Device Independent Pixels
)簡稱DIP
或DP
。上面咱們說,列表的寬度爲300
個像素,實際上咱們能夠說:列表的寬度爲300
個設備獨立像素。
打開chrome
的開發者工具,咱們能夠模擬各個手機型號的顯示狀況,每種型號上面會顯示一個尺寸,好比iPhone X
顯示的尺寸是375x812
,實際iPhone X
的分辨率會比這高不少,這裏顯示的就是設備獨立像素。
設備像素比device pixel ratio
簡稱dpr
,即物理像素和設備獨立像素的比值。
在web
中,瀏覽器爲咱們提供了window.devicePixelRatio
來幫助咱們獲取dpr
。
在css
中,可使用媒體查詢min-device-pixel-ratio
,區分dpr
:
@media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2){ }
在React Native
中,咱們也可使用PixelRatio.get()
來獲取DPR
。
固然,上面的規則也有例外,iPhone 六、七、8 Plus
的實際物理像素是1080 x 1920
,在開發者工具中咱們能夠看到:它的設備獨立像素是414 x 736
,設備像素比爲3
,設備獨立像素和設備像素比的乘積並不等於1080 x 1920
,而是等於1242 x 2208
。
實際上,手機會自動把1242 x 2208
個像素點塞進1080 * 1920
個物理像素點來渲染,咱們不用關心這個過程,而1242 x 2208
被稱爲屏幕的設計像素
。咱們開發過程當中也是以這個設計像素
爲準。
實際上,從蘋果提出視網膜屏幕開始,纔出現設備像素比這個概念,由於在這以前,移動設備都是直接使用物理像素來進行展現。
緊接着,Android
一樣使用了其餘的技術方案來實現DPR
大於1
的屏幕,不過原理是相似的。因爲Android
屏幕尺寸很是多、分辨率高低跨度很是大,不像蘋果只有它本身的幾款固定設備、尺寸。因此,爲了保證各類設備的顯示效果,Android
按照設備的像素密度將設備分紅了幾個區間:
固然,全部的Android
設備不必定嚴格按照上面的分辨率,每一個類型可能對應幾種不一樣分辨率,因此,每一個Android
手機都能根據給定的區間範圍,肯定本身的DPR
,從而擁有相似的顯示。固然,僅僅是相似,因爲各個設備的尺寸、分辨率上的差別,設備獨立像素也不會徹底相等,因此各類Android
設備仍然不能作到在展現上徹底相等。
在iOS
、Android
和React Native
開發中樣式單位其實都使用的是設備獨立像素。
iOS
的尺寸單位爲pt
,Android
的尺寸單位爲dp
,React Native
中沒有指定明確的單位,它們其實都是設備獨立像素dp
。
在使用React Native
開發App
時,UI
給咱們的原型圖通常是基於iphone6
的像素給定的。
爲了適配全部機型,咱們在寫樣式時須要把物理像素轉換爲設備獨立像素:例如:若是給定一個元素的高度爲200px
(這裏的px
指物理像素,非CSS
像素),iphone6
的設備像素比爲2
,咱們給定的height
應爲200px/2=100dp
。
固然,最好的是,你能夠和設計溝通好,全部的UI
圖都按照設備獨立像素來出。
咱們還能夠在代碼(React Native
)中進行px
和dp
的轉換:
import {PixelRatio } from 'react-native'; const dpr = PixelRatio.get(); /** * px轉換爲dp */ export function pxConvertTodp(px) { return px / dpr; } /** * dp轉換爲px */ export function dpConvertTopx(dp) { return PixelRatio.getPixelSizeForLayoutSize(dp); }
在寫CSS
時,咱們用到最多的單位是px
,即CSS像素
,當頁面縮放比例爲100%
時,一個CSS像素
等於一個設備獨立像素。
可是CSS像素
是很容易被改變的,當用戶對瀏覽器進行了放大,CSS像素
會被放大,這時一個CSS像素
會跨越更多的物理像素。
頁面的縮放係數 = CSS像素 / 設備獨立像素
。
這裏多說兩句Retina
屏幕,由於我在不少文章中看到對Retina
屏幕的誤解。
Retina
屏幕只是蘋果提出的一個營銷術語:
在普通的使用距離下,人的肉眼沒法分辨單個的像素點。
爲何強調普通的使用距離下
呢?咱們來看一下它的計算公式:
a
表明人眼視角,h
表明像素間距,d
表明肉眼與屏幕的距離,符合以上條件的屏幕可使肉眼看不見單個物理像素點。
它不能單純的表達分辨率和PPI
,只能一種表達視覺效果。
讓多個物理像素渲染一個獨立像素只是Retina
屏幕爲了達到效果而使用的一種技術。而不是全部DPR > 1
的屏幕就是Retina
屏幕。
好比:給你一塊超大尺寸的屏幕,即便它的PPI
很高,DPR
也很高,在近距離你也能看清它的像素點,這就不算Retina
屏幕。
咱們常常見到用K
和P
這個單位來形容屏幕:
P
表明的就是屏幕縱向的像素個數,1080P
即縱向有1080
個像素,分辨率爲1920X1080
的屏幕就屬於1080P
屏幕。
咱們平時所說的高清屏其實就是屏幕的物理分辨率達到或超過1920X1080
的屏幕。
K
表明屏幕橫向有幾個1024
個像素,通常來說橫向像素超過2048
就屬於2K
屏,橫向像素超過4096
就屬於4K
屏。
視口(viewport
)表明當前可見的計算機圖形區域。在Web
瀏覽器術語中,一般與瀏覽器窗口相同,但不包括瀏覽器的UI
, 菜單欄等——即指你正在瀏覽的文檔的那一部分。
通常咱們所說的視口共包括三種:佈局視口、視覺視口和理想視口,它們在屏幕適配中起着很是重要的做用。
佈局視口(layout viewport
):當咱們以百分比來指定一個元素的大小時,它的計算值是由這個元素的包含塊計算而來的。當這個元素是最頂級的元素時,它就是基於佈局視口來計算的。
因此,佈局視口是網頁佈局的基準窗口,在PC
瀏覽器上,佈局視口就等於當前瀏覽器的窗口大小(不包括borders
、margins
、滾動條)。
在移動端,佈局視口被賦予一個默認值,大部分爲980px
,這保證PC
的網頁能夠在手機瀏覽器上呈現,可是很是小,用戶能夠手動對網頁進行放大。
咱們能夠經過調用document.documentElement.clientWidth / clientHeight
來獲取佈局視口大小。
視覺視口(visual viewport
):用戶經過屏幕真實看到的區域。
視覺視口默認等於當前瀏覽器的窗口大小(包括滾動條寬度)。
當用戶對瀏覽器進行縮放時,不會改變佈局視口的大小,因此頁面佈局是不變的,可是縮放會改變視覺視口的大小。
例如:用戶將瀏覽器窗口放大了200%
,這時瀏覽器窗口中的CSS像素
會隨着視覺視口的放大而放大,這時一個CSS
像素會跨越更多的物理像素。
因此,佈局視口會限制你的CSS
佈局而視覺視口決定用戶具體能看到什麼。
咱們能夠經過調用window.innerWidth / innerHeight
來獲取視覺視口大小。
佈局視口在移動端展現的效果並非一個理想的效果,因此理想視口(ideal viewport
)就誕生了:網站頁面在移動端展現的理想大小。
如上圖,咱們在描述設備獨立像素時曾使用過這張圖,在瀏覽器調試移動端時頁面上給定的像素大小就是理想視口大小,它的單位正是設備獨立像素。
上面在介紹CSS像素時
曾經提到頁面的縮放係數 = CSS像素 / 設備獨立像素
,實際上說頁面的縮放係數 = 理想視口寬度 / 視覺視口寬度
更爲準確。
因此,當頁面縮放比例爲100%
時,CSS像素 = 設備獨立像素
,理想視口 = 視覺視口
。
咱們能夠經過調用screen.width / height
來獲取理想視口大小。
<meta>
元素表示那些不能由其它HTML
元相關元素之一表示的任何元數據信息,它能夠告訴瀏覽器如何解析頁面。
咱們能夠藉助<meta>
元素的viewport
來幫助咱們設置視口、縮放等,從而讓移動端獲得更好的展現效果。
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1; minimum-scale=1; user-scalable=no;">
上面是viewport
的一個配置,咱們來看看它們的具體含義:
Value |
可能值 | 描述 |
---|---|---|
width |
正整數或device-width |
以pixels (像素)爲單位, 定義佈局視口的寬度。 |
height |
正整數或device-height |
以pixels (像素)爲單位, 定義佈局視口的高度。 |
initial-scale |
0.0 - 10.0 |
定義頁面初始縮放比率。 |
minimum-scale |
0.0 - 10.0 |
定義縮放的最小值;必須小於或等於maximum-scale 的值。 |
maximum-scale |
0.0 - 10.0 |
定義縮放的最大值;必須大於或等於minimum-scale 的值。 |
user-scalable |
一個布爾值(yes 或者no ) |
若是設置爲 no ,用戶將不能放大或縮小網頁。默認值爲 yes。 |
爲了在移動端讓頁面得到更好的顯示效果,咱們必須讓佈局視口、視覺視口都儘量等於理想視口。
device-width
就等於理想視口的寬度,因此設置width=device-width
就至關於讓佈局視口等於理想視口。
因爲initial-scale = 理想視口寬度 / 視覺視口寬度
,因此咱們設置initial-scale=1;
就至關於讓視覺視口等於理想視口。
這時,1個CSS
像素就等於1個設備獨立像素,並且咱們也是基於理想視口來進行佈局的,因此呈現出來的頁面佈局在各類設備上都能大體類似。
上面提到width
能夠決定佈局視口的寬度,實際上它並非佈局視口的惟一決定性因素,設置initial-scale
也有肯能影響到佈局視口,由於佈局視口寬度取的是width
和視覺視口寬度的最大值。
例如:若手機的理想視口寬度爲400px
,設置width=device-width
,initial-scale=2
,此時視覺視口寬度 = 理想視口寬度 / initial-scale
即200px
,佈局視口取二者最大值即device-width
400px
。
若設置width=device-width
,initial-scale=0.5
,此時視覺視口寬度 = 理想視口寬度 / initial-scale
即800px
,佈局視口取二者最大值即800px
。
瀏覽器爲咱們提供的獲取窗口大小的API
有不少,下面咱們再來對比一下:
window.innerHeight
:獲取瀏覽器視覺視口高度(包括垂直滾動條)。window.outerHeight
:獲取瀏覽器窗口外部的高度。表示整個瀏覽器窗口的高度,包括側邊欄、窗口鑲邊和調正窗口大小的邊框。window.screen.Height
:獲取獲屏幕取理想視口高度,這個數值是固定的,設備的分辨率/設備像素比
window.screen.availHeight
:瀏覽器窗口可用的高度。document.documentElement.clientHeight
:獲取瀏覽器佈局視口高度,包括內邊距,但不包括垂直滾動條、邊框和外邊距。document.documentElement.offsetHeight
:包括內邊距、滾動條、邊框和外邊距。document.documentElement.scrollHeight
:在不使用滾動條的狀況下適合視口中的全部內容所需的最小寬度。測量方式與clientHeight
相同:它包含元素的內邊距,但不包括邊框,外邊距或垂直滾動條。爲了適配各類屏幕,咱們寫代碼時通常使用設備獨立像素來對頁面進行佈局。
而在設備像素比大於1
的屏幕上,咱們寫的1px
其實是被多個物理像素渲染,這就會出現1px
在有些屏幕上看起來很粗的現象。
基於media
查詢判斷不一樣的設備像素比給定不一樣的border-image
:
.border_1px{ border-bottom: 1px solid #000; } @media only screen and (-webkit-min-device-pixel-ratio:2){ .border_1px{ border-bottom: none; border-width: 0 0 1px 0; border-image: url(../img/1pxline.png) 0 0 2 0 stretch; } }
和border-image
相似,準備一張符合條件的邊框背景圖,模擬在背景上。
.border_1px{ border-bottom: 1px solid #000; } @media only screen and (-webkit-min-device-pixel-ratio:2){ .border_1px{ background: url(../img/1pxline.png) repeat-x left bottom; background-size: 100% 1px; } }
上面兩種都須要單獨準備圖片,並且圓角不是很好處理,可是能夠應對大部分場景。
基於media
查詢判斷不一樣的設備像素比對線條進行縮放:
.border_1px:before{ content: ''; position: absolute; top: 0; height: 1px; width: 100%; background-color: #000; transform-origin: 50% 0%; } @media only screen and (-webkit-min-device-pixel-ratio:2){ .border_1px:before{ transform: scaleY(0.5); } } @media only screen and (-webkit-min-device-pixel-ratio:3){ .border_1px:before{ transform: scaleY(0.33); } }
這種方式能夠知足各類場景,若是須要知足圓角,只須要給僞類也加上border-radius
便可。
上面咱們border-image
和background-image
均可以模擬1px
邊框,可是使用的都是位圖,還須要外部引入。
藉助PostCSS
的postcss-write-svg
咱們能直接使用border-image
和background-image
建立svg
的1px
邊框:
@svg border_1px { height: 2px; @rect { fill: var(--color, black); width: 100%; height: 50%; } } .example { border: 1px solid transparent; border-image: svg(border_1px param(--color #00b1ff)) 2 2 stretch; }
編譯後:
.example { border: 1px solid transparent; border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch; }
上面的方案是大漠在他的文章中推薦使用的,基本能夠知足全部場景,並且不須要外部引入,這是我我的比較喜歡的一種方案。
經過設置縮放,讓CSS
像素等於真正的物理像素。
例如:當設備像素比爲3
時,咱們將頁面縮放1/3
倍,這時1px
等於一個真正的屏幕像素。
const scale = 1 / window.devicePixelRatio; const viewport = document.querySelector('meta[name="viewport"]'); if (!viewport) { viewport = document.createElement('meta'); viewport.setAttribute('name', 'viewport'); window.document.head.appendChild(viewport); } viewport.setAttribute('content', 'width=device-width,user-scalable=no,initial-scale=' + scale + ',maximum-scale=' + scale + ',minimum-scale=' + scale);
實際上,上面這種方案是早先flexible
採用的方案。
固然,這樣作是要付出代價的,這意味着你頁面上全部的佈局都要按照物理像素來寫。這顯然是不現實的,這時,咱們能夠藉助flexible
或vw、vh
來幫助咱們進行適配。
儘管咱們可使用設備獨立像素來保證各個設備在不一樣手機上顯示的效果相似,但這並不能保證它們顯示徹底一致,咱們須要一種方案來讓設計稿獲得更完美的適配。
flexible
方案是阿里早期開源的一個移動端適配解決方案,引用flexible
後,咱們在頁面上統一使用rem
來佈局。
它的核心代碼很是簡單:
// set 1rem = viewWidth / 10 function setRemUnit () { var rem = docEl.clientWidth / 10 docEl.style.fontSize = rem + 'px' } setRemUnit();
rem
是相對於html
節點的font-size
來作計算的。
咱們經過設置document.documentElement.style.fontSize
就能夠統一整個頁面的佈局標準。
上面的代碼中,將html
節點的font-size
設置爲頁面clientWidth
(佈局視口)的1/10
,即1rem
就等於頁面佈局視口的1/10
,這就意味着咱們後面使用的rem
都是按照頁面比例來計算的。
這時,咱們只須要將UI
出的圖轉換爲rem
便可。
以iPhone6
爲例:佈局視口爲375px
,則1rem = 37.5px
,這時UI
給定一個元素的寬爲75px
(設備獨立像素),咱們只須要將它設置爲75 / 37.5 = 2rem
。
固然,每一個佈局都要計算很是繁瑣,咱們能夠藉助PostCSS
的px2rem
插件來幫助咱們完成這個過程。
下面的代碼能夠保證在頁面大小變化時,佈局能夠自適應,當觸發了window
的resize
和pageShow
事件以後自動調整html
的fontSize
大小。
// reset rem unit on page resize window.addEventListener('resize', setRemUnit)window.addEventListener('pageshow', function (e) { if (e.persisted) { setRemUnit() } })
因爲viewport
單位獲得衆多瀏覽器的兼容,上面這種方案如今已經被官方棄用:
lib-flexible這個過渡方案已經能夠放棄使用,無論是如今的版本仍是之前的版本,都存有必定的問題。建議你們開始使用viewport來替代此方案。
下面咱們來看看如今最流行的vh、vw
方案。
vh、vw
方案即將視覺視口寬度 window.innerWidth
和視覺視口高度 window.innerHeight
等分爲 100 份。
上面的flexible
方案就是模仿這種方案,由於早些時候vw
尚未獲得很好的兼容。
vw(Viewport's width)
:1vw
等於視覺視口的1%
vh(Viewport's height)
: 1vh
爲視覺視口高度的1%
vmin
: vw
和 vh
中的較小值vmax
: 選取 vw
和 vh
中的較大值
若是視覺視口爲375px
,那麼1vw = 3.75px
,這時UI
給定一個元素的寬爲75px
(設備獨立像素),咱們只須要將它設置爲75 / 3.75 = 20vw
。
這裏的比例關係咱們也不用本身換算,咱們可使用PostCSS
的 postcss-px-to-viewport
插件幫咱們完成這個過程。寫代碼時,咱們只須要根據UI
給的設計圖寫px
單位便可。
固然,沒有一種方案是十全十美的,vw
一樣有必定的缺陷:
px
轉換成vw
不必定能徹底整除,所以有必定的像素差。vw
,margin
採用px
時,很容易形成總體寬度超過100vw
,從而影響佈局效果。固然咱們也是能夠避免的,例如使用padding
代替margin
,結合calc()
函數使用等等...iPhoneX
的出現將手機的顏值帶上了一個新的高度,它取消了物理按鍵,改爲了底部的小黑條,可是這樣的改動給開發者適配移動端又增長了難度。
在iPhoneX
發佈後,許多廠商相繼推出了具備邊緣屏幕的手機。
這些手機和普通手機在外觀上無外乎作了三個改動:圓角(corners
)、劉海(sensor housing
)和小黑條(Home Indicator
)。爲了適配這些手機,安全區域這個概念變誕生了:安全區域就是一個不受上面三個效果的可視窗口範圍。
爲了保證頁面的顯示效果,咱們必須把頁面限制在安全範圍內,可是不影響總體效果。
viewport-fit
是專門爲了適配iPhoneX
而誕生的一個屬性,它用於限制網頁如何在安全區域內進行展現。
contain
: 可視窗口徹底包含網頁內容
cover
:網頁內容徹底覆蓋可視窗口
默認狀況下或者設置爲auto
和contain
效果相同。
咱們須要將頂部和底部合理的擺放在安全區域內,iOS11
新增了兩個CSS
函數env、constant
,用於設定安全區域與邊界的距離。
函數內部能夠是四個常量:
safe-area-inset-left
:安全區域距離左邊邊界距離safe-area-inset-right
:安全區域距離右邊邊界距離safe-area-inset-top
:安全區域距離頂部邊界距離safe-area-inset-bottom
:安全區域距離底部邊界距離注意:咱們必須指定viweport-fit
後才能使用這兩個函數:
<meta name="viewport" content="viewport-fit=cover">
constant
在iOS < 11.2
的版本中生效,env
在iOS >= 11.2
的版本中生效,這意味着咱們每每要同時設置他們,將頁面限制在安全區域內:
body { padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); }
當使用底部固定導航欄時,咱們要爲他們設置padding
值:
{ padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); }
不少視口咱們要對橫屏和豎屏顯示不一樣的佈局,因此咱們須要檢測在不一樣的場景下給定不一樣的樣式:
window.orientation
:獲取屏幕旋轉方向
window.addEventListener("resize", ()=>{ if (window.orientation === 180 || window.orientation === 0) { // 正常方向或屏幕旋轉180度 console.log('豎屏'); }; if (window.orientation === 90 || window.orientation === -90 ){ // 屏幕順時鐘旋轉90度或屏幕逆時針旋轉90度 console.log('橫屏'); } });
@media screen and (orientation: portrait) { /*豎屏...*/ } @media screen and (orientation: landscape) { /*橫屏...*/ }
咱們平時使用的圖片大多數都屬於位圖(png、jpg...
),位圖由一個個像素點構成的,每一個像素都具備特定的位置和顏色值:
理論上,位圖的每一個像素對應在屏幕上使用一個物理像素來渲染,才能達到最佳的顯示效果。
而在dpr > 1
的屏幕上,位圖的一個像素可能由多個物理像素來渲染,然而這些物理像素點並不能被準確的分配上對應位圖像素的顏色,只能取近似值,因此相同的圖片在dpr > 1
的屏幕上就會模糊:
爲了保證圖片質量,咱們應該儘量讓一個屏幕像素來渲染一個圖片像素,因此,針對不一樣DPR
的屏幕,咱們須要展現不一樣分辨率的圖片。
如:在dpr=2
的屏幕上展現兩倍圖(@2x)
,在dpr=3
的屏幕上展現三倍圖(@3x)
。
使用media
查詢判斷不一樣的設備像素比來顯示不一樣精度的圖片:
.avatar{ background-image: url(conardLi_1x.png); } @media only screen and (-webkit-min-device-pixel-ratio:2){ .avatar{ background-image: url(conardLi_2x.png); } } @media only screen and (-webkit-min-device-pixel-ratio:3){ .avatar{ background-image: url(conardLi_3x.png); } }
只適用於背景圖
使用image-set
:
.avatar { background-image: -webkit-image-set( "conardLi_1x.png" 1x, "conardLi_2x.png" 2x ); }
只適用於背景圖
使用img
標籤的srcset
屬性,瀏覽器會自動根據像素密度匹配最佳顯示圖片:
<img src="conardLi_1x.png" srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">
使用window.devicePixelRatio
獲取設備像素比,遍歷全部圖片,替換圖片地址:
const dpr = window.devicePixelRatio; const images = document.querySelectorAll('img'); images.forEach((img)=>{ img.src.replace(".", `@${dpr}x.`); })
SVG
的全稱是可縮放矢量圖(Scalable Vector Graphics
)。不一樣於位圖的基於像素,SVG
則是屬於對圖像的形狀描述,因此它本質上是文本文件,體積較小,且無論放大多少倍都不會失真。
除了咱們手動在代碼中繪製svg
,咱們還能夠像使用位圖同樣使用svg
圖片:
<img src="conardLi.svg"> <img src="data:image/svg+xml;base64,[data]"> .avatar { background: url(conardLi.svg); }
但願你閱讀本篇文章後能夠達到如下幾點:
文中若有錯誤,歡迎在評論區指正,若是這篇文章幫助到了你,歡迎點贊和關注。
想閱讀更多優質文章、可關注個人github博客,你的star✨、點贊和關注是我持續創做的動力!
推薦關注個人微信公衆號【code祕密花園】,天天推送高質量文章,咱們一塊兒交流成長。