在開發中,我們常用的幾個尺寸的單位,就是px,rem,微信小程序中會用到rpx,可能你不理解它們的關系也能用起來,但想避過與單位有關的一些坑,你就得深入理解他們。
px和物理像素
顯示的原理就是把要顯示的數據寫入顯存區域,然后顯示設備讀取這些數據,驅動硬件就可以顯示了。顯示的數據是以像素為單位的,一個像素只能顯示一種顏色,但是根據顯示顏色的總數不同,每個像素占的位數也不同。如果我想顯示黑白,那一位就可以存儲了,但如果我想顯示16種顏色,就得4位來存儲一個顏色,這樣的一個存儲單位就叫做物理像素
。
我們寫樣式時一個像素記作1px,但是css的px和物理像素是一一對應的嗎,是同樣的概念么?在pc端是這樣的,因為屏幕足夠大,一個css像素用一個物理像素來顯示,完全可以,pc端默認情況下一個css像素就對應著一個物理像素,但是有沒有發現你把分辨率調小以后,顯示的內容變大了,但是顯示器的物理像素肯定不會變啊,這時候其實就是一個css像素對應著若干個物理像素了,這個是與用戶設置有關。
移動設備大小是有限的,而且分辨率不低,甚至比pc端更高,也就是可以顯示的物理像素更多,如果和pc端一樣,一個css的px和物理像素一一對應,可以想象,顯示的內容有多小。這樣肯定是不行的,解決這個問題,我們可以很自然的想到,那在移動設備上就別一一對應了,一個css的px對應多個物理像素吧,這樣就不至于顯示的內容過小了,實際上移動設備也是這么做的,你在開發時寫的px和最終渲染顯示的物理像素數不是一比一的,可能一個px對應2個物理像素,可能3個物理像素,設備顯示的物理像素數和你css的px數的比值就叫做設備像素比(device pixel radio),簡稱dpr。好了,這樣顯示內容過小的問題就解決了。
有了dpr之后,有一個問題就是同樣的一張圖片,我設了寬高的px數,那么在dpr為1的設備上,和dpr為2的設備上顯示的效果是一樣的,1個px在dpr為1的設備上會用1個物理像素來顯示,在dpr為2的設備上會用2*2個物理像素來顯示,這樣dpr高的優勢就體現不出來了,我設備比他的好,你給我的體驗是一樣的,可能有些用戶不爽,我們可以區分對待,對于高dpr的設備,用物理像素更多的高清圖片來替代,也就是2x圖,3x圖等等。
rem和rpx
rem
移動設備的寬度是各種各樣的,每個設備的dpr也不同,換句話說就是不同設備每一行的物理像素數不同,能顯示的css的px數也不同,如果我們寫死px的話,那么后果就是同樣的px,在不同設備中顯示的行數不同,這樣整個排版就亂了,想想有啥解決的思路沒?
分析一下造成顯示效果不同的原因就是設備寬度不同,你可能會問,那dpr呢,其實與dpr一點關系都沒有,想象一下2個寬度為1000個物理像素的設備,一個dpr為1,一個dpr為2,那么在我們看來不過一個是1000px,一個是500px而已,在這里我們感知不到dpr。那么設備寬度不同怎么做適配呢,其實很容易的會想到,每個設備每行顯示的px數不同,你寫死px數的話,那肯定顯示的效果不一樣,所以,不能寫死,要動態的計算。對,實際上也是這么解決的,那怎么計算呢,很簡單,你把一個設備的樣式寫好了,其他的根據設備的寬度(px數)的比,來動態計算就行了。
rem就是解決這個問題的,rem不是具體的px,rem具體顯示多少像素,是根據根元素的font-size來計算的,比如說你設置了1.2rem,根元素的font-size是100px,那么這個元素動態算出來的px數就是120px。不同寬度,設置不同px,這樣就可以適配所有寬度的設備了。看一下實際開發中我們動態計算根元素font-size的代碼:
先來個偽代碼:
var 根元素fontsize = 實際設備寬度 / 開發時設備寬度 * 開發時根元素font-size
具體代碼是:(假設開發時我們適配的是iphone6,也就是375px的設備,我們開發時根元素font-size設為了100px)
document.documentElement.style.fontSize =
(document.documentElement.offsetWidth/375)*100 + 'px' ;
這樣就可以了,其實我們還可以再除以2,為什么呢,因為我們現在設計稿量出來的是物理像素,iphone6的dpr是2,我們要把量出來的數除以2,就是實際的px,然后再除以100,就是rem,既然每次都要這么做,為什么不在根元素這里把除以2給統一做了,只需要把量出的數只要除以100就是rem了。挺完美,現在基本也是用的這種方案。
其實除了根據設備寬度比例計算具體px還有一種思路,我們可以根據設備寬度不同,給不同元素設置不同的px不就行了,這也是一種思路,媒體查詢可以做到這個,也有些網站是這么做的,但是這樣不能兼顧所有的設備,因為你不可能設置很多套樣式,只會在關鍵的幾個設備寬,設置幾套,而動態計算的方式,可以適配所有的寬度。
rpx
微信小程序開發時用的是前端的技術,類似html的組件標簽,css,js,他面臨的問題和網頁一樣,就是不同寬度的設備的適配,解決思路當然也是一樣,但是有一點不同的是不能用rem,為什么呢,因為根本就沒有html元素啊,咋解決,很簡單,我不基于html的font-size了,我基于一個別的值就行了,你也不需要計算這個值,我給你計算了,這就是rpx。最終的效果就是,你開發時在iphon6的設計稿上量了多少px,就寫多少rpx就行了,完美適配,perfect!
一些坑
其實這個看似完美的方案也會帶來一些問題,比如說,我根據rem乘以根元素font-size算出的px值有小數,最終是零點幾px咋辦,不同瀏覽器對這個支持程度不同,有的只渲染出零點幾px對應的物理像素,有的干脆都顯示1px,后果就是,同樣的rem值,在不同dpr的設備上寬度不同,最常見的就是邊框,有的設備上顯得特寬,特別扭,也就是經典的1px邊框問題。這個問題的解決方案也有很多,可以通過設置1px,然后根據不同dpr,設置不同的縮放來做,當然也有其他的方案。我這里只是想說rem帶來的一些問題。
像素比和寬度比
像素比:dpr是設備像素比,也就是css的設備無關像素px和物理像素的比
寬度比:開發適配的設備的寬度(現在一般是iphone6),和實際的設備的寬度的比
總的來說,可以一句話來總結,像素比實現高清,寬度比實現適配