web 中的 viewport 問(wèn)題

你是不是被 Web 布局中的各種 viewport 概念搞蒙,不但如此,你還得去考慮網(wǎng)頁(yè)有放大縮小的情況,更氣人的是 Mobile 側(cè)和 PC 側(cè)很多表現(xiàn)竟然不一樣。本篇就帶你一同探討下這些問(wèn)題。

px

css 中的 px 并不代表一個(gè)屏幕的物理像素,而是一個(gè)邏輯像素。比如我們寫(xiě)了一個(gè) 10 X 10 px 的方塊,如果我們此時(shí)進(jìn)行放大(ctrl+)操作,讓整個(gè)網(wǎng)頁(yè)變?yōu)?200%,那會(huì)發(fā)現(xiàn)這個(gè)方塊在屏幕上長(zhǎng)寬也各增大了一倍,那么同樣代碼的 10x10 對(duì)應(yīng)占用的物理像素變?yōu)榱嗽瓉?lái)的 4 倍(長(zhǎng)寬各 2 倍)。所以 css 中的 px 并不是物理像素,這樣更加靈活。后來(lái)瀏覽器還引入了 devicePixelRatio,同樣 px 即使在高分辨率的顯示屏幕上也不會(huì)出現(xiàn)問(wèn)題,因?yàn)闀?huì)乘以這個(gè)系數(shù)來(lái)作為真實(shí)的物理像素。

window.innerWidth

在 PC 瀏覽器上,當(dāng)你放大、縮小網(wǎng)頁(yè)時(shí),你會(huì)發(fā)現(xiàn) innerWidth 和 innerHeight 會(huì)隨著改變,放大時(shí) innerWidth 會(huì)變小,這是為啥呢?innerWidth 的官方定義如下:

The read-only Window property **innerWidth** returns the interior width of the window in pixels. This includes the width of the vertical scroll bar, if one is present.

所以 innerWidth 和 innerHeight 表現(xiàn)的是網(wǎng)頁(yè)的布局區(qū)域的像素值,如果網(wǎng)頁(yè)整體放大,那么同樣的物理區(qū)域內(nèi)顯示的像素當(dāng)然就變少了,進(jìn)而導(dǎo)致了 innerWidth 變小。官方定義還有下面一句話(huà):

More precisely, innerWidth returns the width of the window's layout viewport.

layout viewport 和 visual viewport

繼續(xù)先來(lái)一段官方解釋。

The layout viewport is the viewport into which the browser draws a web page. Essentially, it represents what is available to be seen, while the visual viewport represents what is currently visible on the user's display device.

通俗來(lái)講,layout viewport 表示一個(gè)可見(jiàn)布局,這個(gè)可見(jiàn)布局里的內(nèi)容并不一定當(dāng)前可見(jiàn),當(dāng)前可見(jiàn)的部分有被稱(chēng)為 visual viewport。

此時(shí)我們回顧下剛剛介紹 px 時(shí)使用的放大縮小能力,PC 側(cè)和移動(dòng)側(cè)放大縮小功能是不一樣的,而且它們的作用也不同。在 PC 側(cè)的瀏覽器,我們可以通過(guò)瀏覽器的 zoom 功能。


而在移動(dòng)端,我們需要用兩指縮放、或用單指雙擊的方式。這種方式并不會(huì)引起 window.innerWidth 的變化。也就是說(shuō)移動(dòng)側(cè)的 layout viewport 不變,會(huì)變動(dòng)只是 visual viewport。文檔也證實(shí)了這一說(shuō)法

This becomes important, for example, on mobile devices, where a pinching gesture can usually be used to zoom in and out on a site's contents. The rendered document doesn't change in any way, so the layout viewport remains the same as the user adjusts the zoom level. Instead, the visual viewport is updated to indicate the area of the page that they can see.

當(dāng)網(wǎng)頁(yè)完全縮放塞滿(mǎn)整個(gè)屏幕時(shí),layout viewport === visual viewport。而當(dāng)兩指放大時(shí),visual viewport 要小于 layout viewport。

viewport

移動(dòng)端布局中用到一個(gè) name 為 viewport 的 meta,此 viewport 和剛剛所提到的 layout viewport 和 visual viewport 并不同。此屬性的作用是約束整個(gè)網(wǎng)頁(yè)布局 html 的大小。所以你可以通過(guò)以下兩個(gè)屬性獲得他的大小。

document.documentElement.clientWidth
document.documentElement.clientHeight

PC 側(cè)的瀏覽視窗大小是可以隨意變動(dòng)的,所以在 PC 側(cè),此屬性設(shè)置無(wú)效,PC 側(cè)的 window.innerWidth === document.documentElement.clientWidth。而到移動(dòng)端就不一樣了,移動(dòng)端的瀏覽器往往占據(jù)整個(gè)屏幕,你無(wú)法調(diào)整視窗的比例和大小,此時(shí)定義 viewport 就有作用了。并且為了能在移動(dòng)設(shè)備上顯示老的 PC 側(cè)頁(yè)面,移動(dòng)瀏覽器廠(chǎng)商默認(rèn)把這個(gè) viewport 定為了 980px,有些如 IE 定為了 1024px。

例如我寫(xiě)了個(gè)以下例子

<html>
    <body style="margin: 0">
        <div style="width: 100%; font-size: 40px; overflow: hidden; background-color: rgb(220, 220, 220);">12345678912345678912345678</div>
    </body>
</html>

在沒(méi)有加 meta 的情況下,這個(gè) div 長(zhǎng)度為 980,由于移動(dòng)端瀏覽器機(jī)制,針對(duì)這種默認(rèn)場(chǎng)景,瀏覽器會(huì)把整個(gè)網(wǎng)頁(yè)自動(dòng)縮小到占據(jù)屏幕的整個(gè)寬。如果要展示如 PC 側(cè)一樣的大小,則會(huì)出現(xiàn)左右滾動(dòng)條,體驗(yàn)很差。

此時(shí)我們加上 viewport 的 meta,則會(huì)發(fā)現(xiàn)寬度變?yōu)榱似聊坏?320 寬。

<meta name='viewport' content="width=device-width">

viewport 可以用來(lái)改變移動(dòng)端 html 的寬度像素值,此值與屏幕本身的寬度并無(wú)關(guān),只是你可以通過(guò)設(shè)置 width=device-width 的方式讓兩者相同。

另外此 meta 中還有 initial-scale, maximum-scale, minimum-scale, user-scalable 這幾個(gè)配置,user-scalable 及表示用戶(hù)是否可以用兩指縮放。scale 幾個(gè)參數(shù)表示縮放比例,都是相對(duì)于屏幕寬度來(lái)說(shuō)的,所以initial-scale=1.0width=device-width是一樣的意思,如果調(diào)成 0.5,則相當(dāng)于把 width 設(shè)置為了 2 倍 device-width。因?yàn)閮?nèi)容縮小了一倍,那自然viewport就放大了一倍了。

總結(jié)一下

screen.width, screen.height 表示整個(gè)顯示屏幕的邏輯像素寬高;
window.innerWidth, window.innerHeight 表示 layout viewport,在 PC 側(cè)會(huì)隨著瀏覽器窗口和 zoom 效果而變大變小。而在移動(dòng)端側(cè),則表示整個(gè)布局的長(zhǎng)寬,由代碼決定。
visual viewport 真正表示當(dāng)前可以看見(jiàn)的區(qū)域。
meta viewport 可以定義 html 的寬度。

如果你想了解 Android 中的尺寸布局問(wèn)題,可以看:《Android布局中的尺寸單位介紹》

參考:
https://www.quirksmode.org/mobile/viewports.html

最后編輯于
?著作權(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)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 通過(guò)上一篇我們已經(jīng)大概明白viewport是什么,但是viewport并沒(méi)有那么簡(jiǎn)單,一包研究得身心疲憊,腦...
    一包閱讀 589評(píng)論 0 0
  • 視口 PC端:視口指瀏覽器可視化區(qū)域,寬度和瀏覽器窗口的寬度一致。在 CSS 標(biāo)準(zhǔn)文檔中,視口也被稱(chēng)為初始包含塊,...
    moofyu閱讀 1,739評(píng)論 0 0
  • 前言: 本文是在閱讀關(guān)于viewport的兩篇文章后,對(duì)于這些常常忘記和混淆的的知識(shí)有了一定的理解,為了方便以后查...
    lightNate閱讀 1,357評(píng)論 2 5
  • 在移動(dòng)設(shè)備上進(jìn)行網(wǎng)頁(yè)的重構(gòu)或開(kāi)發(fā),首先得搞明白的就是移動(dòng)設(shè)備上的viewport了,只有明白了viewport的概...
    Sun____閱讀 14,631評(píng)論 6 21
  • 開(kāi)發(fā)移動(dòng)網(wǎng)頁(yè)時(shí),你一定會(huì)遇到下面這段代碼: 在網(wǎng)頁(yè)的 中增加以上這句話(huà),可以讓網(wǎng)頁(yè)的寬度自動(dòng)適應(yīng)手機(jī)屏幕的寬度。其...
    gzgogo閱讀 2,448評(píng)論 4 16

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