摘要:不要再問我的問題系列一不要再問我的指向問題了二不要再問我跨域的問題了移動端適配的問題,一般來說我們都不會去深究,因為這種東西都是配置一次就再也不用管的了,接到設(shè)計圖就按照祖?zhèn)魈茁窋]就完事了。
“不要再問我XX的問題”系列:
一、不要再問我this的指向問題了
二、不要再問我跨域的問題了
移動端適配的問題,一般來說我們都不會去深究,因為這種東西都是配置一次就再也不用管的了,接到設(shè)計圖就按照祖?zhèn)魈茁窋]就完事了。按部就班的必定只能成為活動頁寫手,研究透徹以后,才能成為一名專業(yè)的活動頁寫手嘛。
糾纏不清的關(guān)系文章開始,我們需要來捋清楚像素、視口以及縮放之間種種藕斷絲連的關(guān)系,來抽絲剝繭一波。
像素像素我們寫得多了,不就是px嘛,為什么要拿出來說呢?因為像素還不僅僅就是px。
設(shè)備像素
設(shè)備像素也可以叫物理像素,由設(shè)備的屏幕決定,其實就是屏幕中控制顯示的最小單位。
設(shè)備獨立像素
設(shè)備獨立像素是一種可以被程序所控制的虛擬像素,在Web開發(fā)中對應(yīng)CSS像素。
DPR
設(shè)備像素與設(shè)備獨立像素之間的關(guān)系就是,DPR(設(shè)備像素比),設(shè)備像素比 = 設(shè)備像素 / 設(shè)備獨立像素。這條公式成立的前提是,縮放比為1,原因下面講到縮放的時候就會知道。根據(jù)這種關(guān)系,如果設(shè)備像素大于設(shè)備獨立像素(DPR大于1的設(shè)備,我們常說的高清屏或者Retina屏),就會出現(xiàn)一個設(shè)備獨立像素對應(yīng)多個設(shè)備像素的情況:
遙想從前智能手機剛出的時候,很少網(wǎng)站去特意適配移動端,然而用戶是可以直接從手機去訪問PC端網(wǎng)站的,所以怎樣顯示好一個網(wǎng)站,無論這個網(wǎng)站是一個PC網(wǎng)站還是移動端網(wǎng)站,就是亟需解決的問題。所以移動端三個視口布局視口、視覺視口、理想視口橫空出世,成為各種移動適配方案的基礎(chǔ)。
布局視口
布局視口是在html元素之上的容器,我們的頁面就“裝”在布局視口中。
想想我們常寫的width:100%,這個100%是基于什么計算出來的呢?去翻資料會看到:如果某些屬性被賦予一個百分值的話,它的計算值是由這個元素的包含塊計算而來的。那html元素的包含塊是什么呢?沒錯,就是我們的布局視口,它是所有CSS百分比推算的根源,如果說CSS是一支畫筆,那么布局視口就是那張畫布吧。這張畫布有一個默認尺寸(如果沒有手動去設(shè)置meta viewport),一般在768px ~ 1024px間,可以通過document.documentElement.clientWidth獲取。這樣一來,網(wǎng)頁的布局就不再受限于設(shè)備的尺寸,即使是小屏幕的移動端設(shè)備中也能容得下PC網(wǎng)站。
視覺視口
視覺視口是指用戶通過設(shè)備屏幕看到的區(qū)域,可以通過縮放來改變視覺視口的大小,并通過window.innerWidth獲取。
這里有必要講一下縮放,縮放改變的是CSS像素的大小,放大時CSS像素增大,則一個CSS像素可以跨越更多的設(shè)備像素,視覺視口會變小。什么?放大反而視覺視口變小?沒錯,這是因為視覺視口也是通過CSS像素度量,而放大就是使CSS像素放大,假設(shè)屏幕上本來需要200個CSS像素才能占滿屏幕,由于放大,現(xiàn)在只需要100個CSS像素就能占滿,所以視覺視口的寬就變成100px。
雖然縮放改變了CSS像素的大小,但移動端的縮放是不會改變布局視口的,所以縮放并不會影響布局,不過在PC端是會影響布局的。最直觀的感受是,我們平時在移動端雙指縮放網(wǎng)頁,整個網(wǎng)頁的布局是沒有變化的,可以通過拖動來看到不同區(qū)域的東西,但是在PC端進行縮放,比如閱讀時想文字大一些而對網(wǎng)頁進行放大操作,這時字是放大了,但整個頁面的布局會有所改變。那么既然與布局視口無關(guān)那還跟誰有關(guān)系呢?答案就是下面準備要講的理想視口,它們之間的計算方式是:縮放系數(shù) = 理想視口寬度 / 視覺視口寬度
理想視口
理想視口是指網(wǎng)站在移動設(shè)備中的理想大小,這個大小就是設(shè)備的屏幕大小。
為什么需要理想視口呢?首先,先來看看現(xiàn)在的情況是怎么的不理想。我們在瀏覽一個沒經(jīng)過移動適配的網(wǎng)站時,由于布局視口在768px ~ 1024px之間,整個網(wǎng)站就“畫”在一個這么大的“畫布”上,但由于手機屏幕比“畫布”小,所以需要經(jīng)過縮小才能塞進手機屏幕,結(jié)果我們?yōu)g覽網(wǎng)站的時候雖然看得見全貌,但里面的東西都變得很小,需要放大一下才能看得清,就是這么不理想。如果不需要放大就可以看得清那就很理想了嘛。回想一下上面不理想的解決方案,就是將一個大畫布經(jīng)過縮小裝進小屏幕里,假設(shè)現(xiàn)在畫布跟屏幕一樣大,就在這個畫布上作畫,豈不是很合適?
所以總結(jié)起來,理想視口說白了就是理想的布局視口,通過來設(shè)置。
元素可提供有關(guān)頁面的元信息,不會顯示在頁面上,可以用來告訴瀏覽器怎樣解析頁面。可以設(shè)置的東西很多,但這里只講vieport,它是所有移動適配方案的基礎(chǔ)。
首先meta viewport的設(shè)置格式是,其中name的值可設(shè)為:
width:將布局視口設(shè)置為固定的值,比如375px或者device-width(設(shè)備寬度)
initial-scale:設(shè)置頁面的初始縮放
minimum-scale:設(shè)置最小的縮小程度
maximum-scale:設(shè)置最大的放大程度
user-scalable:設(shè)置為no時禁用縮放
雖然只有五個值,但仍有一些值得注意的點:
設(shè)置initial-scale的影響根據(jù)公式縮放系數(shù) = 理想視口寬度 / 視覺視口寬度 ,如果設(shè)置了initial-scale比如為0.5,那么以iPhone6為例,iPhone6的設(shè)備寬度是375px,即理想視口寬度也為375px,所以視覺視口寬度 = 375px(理想視口寬度)/ 0.5(縮放系數(shù))。很明顯設(shè)置了initial-scale就相當(dāng)于初始化了視覺視口,而且會將布局視口初始化為這個視覺視口的值。
width和initial-scale共存上面說到設(shè)置了initial-scale相當(dāng)于初始化了視覺視口和布局視口,但width用于指定布局視口的大小,那么一起設(shè)置的話聽誰的呢?
還是以iPhone6為例,它的尺寸是667(h) * 375(w),如果設(shè)置,執(zhí)行一下console.log(`布局視口: ${document.documentElement.clientWidth}; 視覺視口: ${window.innerWidth}`)會得到“布局視口: 400; 視覺視口: 400”。
這時候旋轉(zhuǎn)一下設(shè)備,這時尺寸變成了667(w) * 375(h),再執(zhí)行一下console.log(`布局視口: ${document.documentElement.clientWidth}; 視覺視口: ${window.innerWidth}`)會得到“布局視口: 667; 視覺視口: 667”。
結(jié)論是:width與initial-scale都會初始化布局視口,但瀏覽器會取其最大值。
這時候再看回,明明width=device-width和initial-scale=1都是去初始化布局視口成理想的布局視口,只寫其中一個不就完了嘛,為什么要兩個都一起寫呢?因為有的瀏覽器只設(shè)置其中一個,不能保證理想視口的尺寸能隨著屏幕的旋轉(zhuǎn)而正確改變,所以兩個一起寫只是為了解決兼容性問題。
舒服地還原移動端設(shè)計圖上面說了很多理論知識,其實就是為了能有一套方案舒服地還原移動端設(shè)計圖,做出一個專為移動端訪問的頁面。
經(jīng)典的問題圖片
這里的圖片問題是指高清/Retina屏下圖片會顯示得比較模糊,這是因為我們平時使用的圖片大多數(shù)是png、jpg這樣格式的圖片,它們稱作是位圖圖像(bitmap),是由一個個像素點構(gòu)成,縮放會失真。上面講像素的時候說過,這種高清/Retina屏DPR大于一,則一像素橫跨了多個設(shè)備像素,而位圖圖像需要一個像素點對應(yīng)一個設(shè)備像素才清晰。所以假設(shè)一張100 x 100的圖片放在普通屏上看是清晰的,放到高清/Retina屏上就會顯得比較模糊,那是因為本來100 x 100的圖片在普通屏上圖片像素與設(shè)備像素一一對應(yīng),而到了高清/Retina屏上一個圖片像素卻要對應(yīng)多個設(shè)備像素,這樣一來看起來圖片就比較模糊。
如圖所示,如果一個圖片像素要對應(yīng)多個設(shè)備像素的話,那這些設(shè)備像素只能顯示成跟這個圖片像素差不多的顏色,導(dǎo)致看起來會模糊。
既然知道了問題產(chǎn)生的原因,那解決方法也很簡單,位圖圖像需要一個像素點對應(yīng)一個設(shè)備像素才清晰嘛,那就本來是100 x 100的圖片在DPR為1的屏幕上顯示清晰,在DPR為2的屏幕上顯示模糊,那就在DPR為2的屏幕上放200 x 200的圖好了,這樣就一一對應(yīng)了。
1px邊框
“你看看設(shè)計圖這根線是很細的,為什么你實現(xiàn)出來那么粗,看起來很劣質(zhì)的感覺?!?br>沒道理呀,設(shè)計圖量的是1px,css寫的也是1px,怎么會粗了呢?一般設(shè)計師出圖的時候,都會按照一個尺寸作為標準來出圖,比如按照iPhone6的尺寸出圖,就是一張750px寬的設(shè)計圖,這個750px其實就是iPhone6的設(shè)備像素,在測量設(shè)計圖時量到的1px其實是1設(shè)備像素,而當(dāng)我們設(shè)置時,布局視口等于理想視口等于375px,并且由于iPhone6的DPR為2,寫css時的1px對應(yīng)的是2設(shè)備像素,所以看起來會粗一點。
那么只要寫0.5px就是對應(yīng)1設(shè)備像素了嘛。是的,道理是這么說,但是很多瀏覽器并不支持0.5px的寫法,導(dǎo)致顯示不出來,但不要緊,網(wǎng)上很多方法解決這個問題的方法就不細說了,這里只是講清楚1px邊框問題產(chǎn)生的原因。
因為PC端屏幕一般都會比設(shè)計圖尺寸要大,所以只需要居中固定一個內(nèi)容區(qū)用于顯示設(shè)計圖的內(nèi)容,其余多出的地方留白即可。而移動端屏幕有大有小,設(shè)計圖一般會以一款機型為標準來出圖,比如說iPhone6的尺寸,如果不經(jīng)處理直接量設(shè)計圖就開干會出現(xiàn)什么問題呢?
(從左到右為iPhone4、iPhone6、iPhone plus)
可以看到以iPhone6為標準出的設(shè)計圖測量出來350px x 350px的元素在iPhone6上寫width: 350px;height: 350px;是剛剛好的,左右的間隙各有10px,但小一點的屏幕iPhone4橫向滾動條都出來了,而plus左右間隙明顯比10px大很多,這樣一來不同尺寸的屏幕出來的效果跟設(shè)計圖的效果就會有不同程度的出入,這并不是我們想要的,我們想要的是不同尺寸的屏幕顯示的效果與設(shè)計圖比例是一致的。
既然想要的是不同屏幕尺寸顯示的比例與設(shè)計圖一致,那么顯然適配方案就是等比縮放。
(以下代碼都是為了講述原理,沒有過多的細節(jié)考慮與測試,不能用于生產(chǎn)環(huán)境)
viewport方案
說到縮放,首先想到的當(dāng)然是initial-scale?;叵胍幌耰nitial-scale的作用:設(shè)置了initial-scale就相當(dāng)于初始化了視覺視口,而且會將布局視口初始化為這個視覺視口的值。那么我們是不是可以以設(shè)計圖為基準等比縮放布局視口從而適配呢?
這種方式進行適配優(yōu)點是簡單粗暴,缺點是太簡單粗暴了,因為viewport的設(shè)置是影響全局的,這樣一來雖然可以直接將設(shè)計圖量得的尺寸寫到css上,但如果有一些需要地方不需要等比縮放而需要設(shè)置固定尺寸,比如要求在不同尺寸屏幕上顯示固定大小的文字,或者你引進了一個庫,里面的有樣式你也不知道人家是按照怎樣的適配方案進行適配的,那么到了你的項目里由于全局的viewport縮放,可能會影響到這個庫的顯示效果。
rem方案
不同于px是固定尺寸單位,rem是相對單位,相對于html標簽字體大小的單位。比如html標簽的font-size為100px,那么1rem就等于100px。借助rem這個相對單位我們同樣可以達到等比縮放的效果。
這個方案不需要對viewport進行縮放,所以首先按照慣例我們讓布局視口等于理想視口:
還是以iPhone6的設(shè)備像素為標準的設(shè)計圖,寬是750px,假設(shè)以設(shè)計圖為標準的html標簽的font-size為100px,所以1rem = 100px,那么這個設(shè)計圖總寬就有7.5rem
以總寬是7.5rem的設(shè)計圖為標準,則不同屏幕尺寸的總寬應(yīng)該也是7.5rem,由于上面設(shè)置了布局視口等于理想視口,所以以iPhone6為例,iPhone6的布局視口等于理想視口,則它的布局視口為375px(也就是總寬7.5rem),現(xiàn)在只需要解決在布局視口為375px的情況下,html的font-size需要設(shè)置多少。很簡單,html font-size * 7.5 = 375,那么font-size為50px。
拓展到其他屏幕document.documentElement.style.fontSize = `${document.documentElement.clientWidth / 7.5}px`
現(xiàn)在我們只需要測量設(shè)計圖,比如設(shè)計圖有一個300px的元素,那我們寫css的時候就寫成3rem(由于以1rem = 100px為基準,所以這里300px / 100即可)
使用這個方案,我們只對需要等比縮放的元素使用rem,而要求固定尺寸的地方使用px即可,這樣一來相對于viewport方案來說就比較靈活,可以按需使用而不是一刀切。不過這種方案寫css的時候可能會沒那么直觀,成本可能會高一點點,但是借助構(gòu)建工具或者less/sass可以解決,畢竟現(xiàn)在應(yīng)該很少項目不使用這些工具的了吧。
加強版rem方案
這里所說的加強版rem方案其實就是手淘的Flexible方案(也類似移動端高清、多屏適配方案),究竟加強了什么呢?那就是,通過設(shè)置viewport進而全局解決1px邊框問題。
既然要通過設(shè)置viewport來解決1px邊框問題,那設(shè)置這個viewport的方式肯定內(nèi)有乾坤:
if (!dpr && !scale) { var isAndroid = win.navigator.appVersion.match(/android/gi); var isIPhone = win.navigator.appVersion.match(/iphone/gi); var devicePixelRatio = win.devicePixelRatio; if (isIPhone) { if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { dpr = 3; } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){ dpr = 2; } else { dpr = 1; } } else { // 其他設(shè)備下,仍舊使用1倍的方案 dpr = 1; } scale = 1 / dpr; }
得出的scale用于設(shè)置viewport的縮放document.write(``),這樣一來,對于Retina屏將viewport縮放為1 / dpr最終產(chǎn)生的效果是,1px css像素嚴格等于1px 設(shè)備像素,由此解決了1px邊框問題。那為什么只對iPhone進行縮放呢?請看大漠老師的文章再談Retina下1px的解決方案。
其他與rem相關(guān)的配置與上面的rem方案類似,這里就不再展開說了。
這個加強版rem方案最大的優(yōu)勢是解決了1px邊框問題,但由此也進行了viewport的縮放,仍然會面臨著上面說的viewport方案涉及到的一些影響,為此該方案會通過給html設(shè)置data-dpr
document.documentElement.setAttribute("data-dpr", dpr)
從而寫css的時候可以針對不同的dpr固定設(shè)置尺寸:
.test { width: 1rem; height: 2rem; font-size: 12px; } [data-dpr="2"] .test { font-size: 13px; } [data-dpr="3"] .test { font-size: 14px; }
vw方案
vw也是一個相對單位,它相對的是布局視口,1vw就是1%的布局視口寬度。其實rem方案就是在模擬vw,來看看使用vw怎么做。
還是熟悉的iPhone6標準設(shè)計圖,寬750px。那么1vw = 1%視口寬度的話,按設(shè)計圖來說就是100vw = 750px,則1vw = 7.5px。
設(shè)計圖量得一個元素是100px,css需要寫成 Xvw * 7.5 = 100,所以X就等于13.3vw。
計算的話還是交給構(gòu)建工具即可,詳細請看再聊移動端頁面的適配
rem方案有的優(yōu)勢vw也有,而且也不會像rem那么繞,但就是兼容性不夠rem好,長遠來看vw最后會接棒rem作為移動適配的主力,因為它生來就干這個事情呢。
終于結(jié)束了沒有銀彈。
全局viewport縮放方案很粗暴?但對于要求不高也不需要兼顧固定尺寸的頁面,上來就全局縮放,拿起設(shè)計稿就可以寫代碼了。要求高又想靈活,還會怕構(gòu)建的那一點點麻煩嗎?rem方案走起。兼容性不需要考慮,那vw方案直白又優(yōu)雅不試試看嗎?方案沒有優(yōu)劣之分只有合適與否。
最后,如果有說得不對的地方,還望指正。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/100769.html
摘要:不要再問我的問題系列一不要再問我的指向問題了二不要再問我跨域的問題了移動端適配的問題,一般來說我們都不會去深究,因為這種東西都是配置一次就再也不用管的了,接到設(shè)計圖就按照祖?zhèn)魈茁窋]就完事了。 不要再問我XX的問題系列:一、不要再問我this的指向問題了二、不要再問我跨域的問題了 移動端適配的問題,一般來說我們都不會去深究,因為這種東西都是配置一次就再也不用管的了,接到設(shè)計圖就按照祖?zhèn)?..
摘要:不要再問我的問題系列一不要再問我的指向問題了二不要再問我跨域的問題了移動端適配的問題,一般來說我們都不會去深究,因為這種東西都是配置一次就再也不用管的了,接到設(shè)計圖就按照祖?zhèn)魈茁窋]就完事了。 不要再問我XX的問題系列:一、不要再問我this的指向問題了二、不要再問我跨域的問題了 移動端適配的問題,一般來說我們都不會去深究,因為這種東西都是配置一次就再也不用管的了,接到設(shè)計圖就按照祖?zhèn)?..
摘要:所以構(gòu)造函數(shù)里的指的就是將要被出來的新對象。希望看完這篇文章之后,再有人問指向的問題,你可以嘴角微微上揚,冷笑一聲不要再問我的指向問題了。 this的指向已經(jīng)是一個老生常談的問題,每逢面試都要去復(fù)習(xí)復(fù)習(xí),近來鞏固js的基礎(chǔ),決心徹底掌握這個知識點,一勞永逸。說明一下,為了不影響大家的思考過程,下面的代碼都不會去注釋答案,想知道答案,只需要去控制臺執(zhí)行一下。 四類場景逐一擊破 首先,分析...
摘要:不過大多數(shù)講解還停留在對功能使用的層面,其底層的很多原理,很多人可能并不知曉。每個線程池里的線程就僅僅用于請求那個服務(wù)。 歡迎關(guān)注微信公眾號:石杉的架構(gòu)筆記(id:shishan100) 每日更新!精品技術(shù)文章準時送上! 目錄 一、業(yè)務(wù)場景介紹 二、Spring Cloud核心組件:Eureka 三、Spring Cloud核心組件:Feign 四、Spring Cloud核心組件:R...
摘要:不過大多數(shù)講解還停留在對功能使用的層面,其底層的很多原理,很多人可能并不知曉。每個線程池里的線程就僅僅用于請求那個服務(wù)。 歡迎關(guān)注微信公眾號:石杉的架構(gòu)筆記(id:shishan100) 每日更新!精品技術(shù)文章準時送上! 目錄 一、業(yè)務(wù)場景介紹 二、Spring Cloud核心組件:Eureka 三、Spring Cloud核心組件:Feign 四、Spring Cloud核心組件:R...
閱讀 3087·2021-11-24 10:47
閱讀 3842·2021-11-02 14:43
閱讀 2235·2021-09-26 10:15
閱讀 2285·2021-09-08 09:35
閱讀 574·2019-08-30 12:45
閱讀 2784·2019-08-29 17:04
閱讀 3218·2019-08-26 14:05
閱讀 1263·2019-08-26 12:10