相關(guān)鏈接:移動(dòng)端適配 — 細(xì)節(jié)補(bǔ)充(一)
Retina屏幕&普通屏幕,模糊的由來
dpr的具體表現(xiàn)
有時(shí)候我們會(huì)發(fā)現(xiàn),當(dāng)我們?cè)谶m某一機(jī)型的時(shí)候,顯示上沒什么問題。但是一旦我換到另外一部手機(jī),發(fā)現(xiàn)出現(xiàn)了模糊的情況,尤其以圖片更為顯著。
其實(shí)這個(gè)問題,就是涉及到了上面講到的一個(gè)屬性:設(shè)備像素比,即我們經(jīng)常說的dpr。下面先來看dpr的表現(xiàn):
假設(shè)現(xiàn)在有一臺(tái)iphone 6,那么它的設(shè)備獨(dú)立像素是375x667,dpr為2,尺寸是4.7in,那么物理像素就是750x1334。同樣的我們也有一臺(tái)不知名的設(shè)備,它的設(shè)備獨(dú)立像素剛好也是375x667,尺寸也是4.7in,但是dpr為1,此時(shí)的物理像素就是375x667。于是,它們的屏幕表現(xiàn)如下:
在不同的屏幕上,無論是普通屏幕還是retina屏幕,css像素所呈現(xiàn)的大小是一致的(如果不理解這句話,可以寫一個(gè)2px的正方形使用谷歌控制臺(tái)移動(dòng)設(shè)備調(diào)試,在不同的設(shè)備之間來回切換,你會(huì)發(fā)現(xiàn)大小其實(shí)是一樣的。一開始我總以為這個(gè)css像素的實(shí)際寬高因?yàn)槭艿絛pr的影響而在不同設(shè)備上的長(zhǎng)寬是不一致的)。
不同的是,1個(gè)css像素對(duì)應(yīng)(覆蓋)的物理像素個(gè)數(shù)。
所以,如果我們想要在這兩個(gè)屏幕顯示這么一個(gè)css樣式:
width: 2px;
heigth: 2px;
在普通屏幕下,也就是dpr為1的屏幕中,1個(gè)css像素對(duì)應(yīng)(覆蓋)的是一個(gè)物理像素。在retina屏幕下,1個(gè)css像素對(duì)應(yīng)(覆蓋)的是4個(gè)物理像素。換句話說,就是dpr為2的設(shè)備??聪旅孢@張圖:
淺顯的理解就是可以看作是2cm x 2cm的正方形被切割成四塊,然后遇到dpr為2的時(shí)候,被切割的四塊又被分別切割成四塊,但是總面積不變。
模糊的產(chǎn)生
知道了1個(gè)css像素覆蓋的物理像素可能不同,就好理解為什么會(huì)出現(xiàn)模糊的情況了。這里又講到一個(gè)名詞:位圖像素。
位圖像素是柵格圖像(如:png,jpg,gif等)最小的數(shù)據(jù)單元。每一個(gè)位圖像素都包含著一些自身的顯示信息。(如:顯示位置,顏色值,透明度等)
理論上來說,1個(gè)位圖像素對(duì)應(yīng)1個(gè)物理像素,圖片才能達(dá)到完美清晰的展示。 但是上面說過,在retina屏幕上,會(huì)出現(xiàn)1個(gè)位圖像素對(duì)應(yīng)多個(gè)物理像素。
還是以iphone 6為例,1個(gè)位圖像素對(duì)應(yīng)4個(gè)物理像素。由于單個(gè)位圖像素已經(jīng)是最小的數(shù)據(jù)單位了,它不能再被進(jìn)行切割。于是為了能夠顯示出來,就只能就近取色,從而導(dǎo)致所謂的圖片模糊問題。如下:
如何解決
很明顯,由于位圖像素不夠分而產(chǎn)生模糊的情況,解決的辦法十分簡(jiǎn)單,就是使用跟dpr同個(gè)倍數(shù)大小的圖片。比如iphone 6,一個(gè)200x300的img標(biāo)簽,原圖就要提供400x600的大小。
那么當(dāng)加載到img標(biāo)簽中,瀏覽器會(huì)自動(dòng)對(duì)每1px 的css 像素減半,可以理解為此時(shí)還是維持著1:1的css像素:物理像素,不產(chǎn)生模糊。這個(gè)做法其實(shí)就是手淘團(tuán)隊(duì)在做retina適配的一個(gè)重要的原理之一,后面會(huì)講到,這里先放著不說。
其他
反向思考一下,如果普通屏幕,也就是dpr為1的屏幕,也使用了兩倍的圖片,會(huì)發(fā)生什么樣的情況呢?
很明顯,在普通屏幕下,200×300的img標(biāo)簽,所對(duì)應(yīng)的物理像素個(gè)數(shù)就是200×300個(gè),而兩倍圖片的位圖像素個(gè)數(shù)則是200x300x4,于是就出現(xiàn)一個(gè)物理像素點(diǎn)對(duì)應(yīng)4個(gè)位圖像素點(diǎn),所以它的取色也只能通過一定的算法進(jìn)行縮減,顯示結(jié)果就是一張只有原圖像素總數(shù)四分之一,肉眼看上去雖然圖片不會(huì)模糊,但是會(huì)覺得有點(diǎn)色差(其實(shí)就是模糊的逆向過程)。
用圖片來表示就是:這里摘取了網(wǎng)上一篇博文的demo來闡述上面所說的問題。
以上是一張100x100的圖片,分別放在了100x100,50x50,25x25的容器中,在retina屏幕下面的顯示效果。
通過取色器放大鏡可以看出邊界像素點(diǎn)的差別:
在圖一中,邊界像素點(diǎn)就近取色,色值介于紅白之間,偏淡,圖片看上去會(huì)模糊(可以理解為圖片拉伸)。
在圖二中,圖片正常,很清晰。
在圖三中,邊界像素點(diǎn)就近取色,色值介于紅白之間,偏濃,圖片看上去有色差。
Retina屏幕下的處理與安卓手機(jī)的適配
分析手淘的flexible.js代碼中可以知道,它布局僅僅只是針對(duì)iPhone進(jìn)行適配,而默認(rèn)所有的安卓設(shè)備都強(qiáng)制性設(shè)置dpr為1。于是,因?yàn)檫@個(gè)緣故,很多小伙伴可能就會(huì)產(chǎn)生這樣的問題:為什么安卓不用retina屏幕,安卓下面是不是就不會(huì)有模糊的問題?
其實(shí)不然,模糊的本質(zhì)是因?yàn)閐pr,而安卓手機(jī)不同的設(shè)備的dpr也是不盡相同的。也就是說,安卓手機(jī)下也存在模糊的情況。只不過它的屏幕不叫retina屏幕,沒有這個(gè)叫法,所以很多小伙伴都誤認(rèn)為安卓手機(jī)沒有這個(gè)毛病。那么問題又來了?既然也有模糊的毛病,那么為什么安卓手機(jī)不進(jìn)行適配呢?
問題就在這里了,有興趣的小伙伴可以去看一下大中華的安卓手機(jī),dpr參數(shù)五花八門,從1到4,連1.75、2.75這種奇葩的數(shù)字也有,所以個(gè)人覺得權(quán)衡之下,直接簡(jiǎn)單“粗暴”把安卓手機(jī)全部設(shè)置為1,是效率和收益更高的做法。
響應(yīng)式與自適應(yīng)的選擇
最后,對(duì)于響應(yīng)式和自適應(yīng)的區(qū)別,網(wǎng)上有各種各樣的解釋。個(gè)人認(rèn)為,其實(shí)沒必要把它講得那么復(fù)雜,知乎上有個(gè)小伙伴講我覺得就很白話文:
響應(yīng)式針對(duì)的是不同分辨率設(shè)備而進(jìn)行的適配式設(shè)計(jì),以利用@media規(guī)則為主要手段,而自適應(yīng)則忽略@media以比例布局為主,目的是適應(yīng)不同的瀏覽器窗口大小。
于是我們會(huì)發(fā)現(xiàn),現(xiàn)今大型網(wǎng)站,例如說淘寶網(wǎng),已經(jīng)沒有做響應(yīng)式了。什么意思呢?我們會(huì)發(fā)現(xiàn),淘寶網(wǎng)手機(jī)端和網(wǎng)頁(yè)端使用的是兩個(gè)域名,也就是說,不同的客戶端已經(jīng)不再共用一套dom結(jié)構(gòu)了。而是區(qū)分開來做自適應(yīng)。然后每次用戶訪問的時(shí)候它就根據(jù)客戶端的類型重定向。
為什么呢?
試想一下淘寶這種大型網(wǎng)站,一個(gè)分頁(yè)下的商品條目特別多,并且每個(gè)商品條目的dom結(jié)構(gòu)又十分復(fù)雜,而且pc端往往顯示的信息是要比手機(jī)端更多的。如果不分開做兩套,而是直接用響應(yīng)式的話,那么pc端上顯示的很多dom就要在手機(jī)端上隱藏,結(jié)果這些dom都沒有被用到,但是卻加載了。在這個(gè)流量和速度至上的時(shí)代,代碼冗余先不說,多加載的這些無用的代碼而消耗的流量,從某種意義上來說就已經(jīng)損失了很多的效益。
最后
考慮到兼容性的問題,原先我們?cè)谖恼骂^部說到的那段代碼:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
從 Chrome32+版本開始是會(huì)默認(rèn)禁用用戶縮放的,但是考慮到兼容大部分設(shè)備,還是要加上其他設(shè)置,讓 meta標(biāo)簽?zāi)軌蛴懈玫娜蒎e(cuò)性。也就是下面這段代碼:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
需要注意的是,在 ios10+以上,盡管開發(fā)者設(shè)置了user-scalable=no, Safari還是允許用戶通過手勢(shì)來縮放。(安卓手機(jī)各大廠商的內(nèi)置瀏覽器也逐漸開放用戶縮放,即使使用meta 標(biāo)簽進(jìn)行設(shè)置)
解決的方法也很簡(jiǎn)單,只需要檢測(cè)touch 相關(guān)事件來阻止事件的觸發(fā)即可。
window.onload = function() {
// 同時(shí)按下兩個(gè)手指
document.addEventListener('touchstart', function(event) {
if(event.touches.length > 1) {
event.preventDefault()
}
})
var lastTouchEnd = 0;
// 特別注意300ms時(shí)差的設(shè)置
document.addEventListener('touchend', function(event) {
var now = (new Date()).getTime();
if(now-lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
})
}
以上,就是本文的全部啦。
原文地址:https://blog.csdn.net/xiaxiaoxian/article/details/79395694