兩個viewport的故事(第一部分)

原文:http://www.quirksmode.org/mobile/viewports.htmlcss

在這個迷你係列的文章裏邊我將會解釋viewport,以及許多重要元素的寬度是如何工做的,好比<html>元素,也包括窗口和屏幕。html

這篇文章是關於桌面瀏覽器的,其惟一的目的就是爲移動瀏覽器中類似的討論作個鋪墊。大部分開發者憑直覺已經明白了大部分桌面瀏覽器中的概念。在移動端咱們將會接觸到相同的概念,可是會更加複雜,因此對你們已經知道的術語作個提早的討論將會對你理解移動瀏覽器產生巨大的幫助。web

概念:設備像素和CSS像素

你須要明白的第一個概念是CSS像素,以及它和設備像素的區別。數據庫

設備像素是咱們直覺上以爲「靠譜」的像素。這些像素爲你所使用的各類設備都提供了正規的分辨率,而且其值能夠(一般狀況下)從screen.width/height屬性中讀出。瀏覽器

若是你給一個元素設置了width: 128px的屬性,而且你的顯示器是1024px寬,當你最大化你的瀏覽器屏幕,這個元素將會在你的顯示器上重複顯示8次(大概是這樣;咱們先忽略那些微妙的地方)。ide

若是用戶進行縮放,那麼計算方式將會發生變化。若是用戶放大到200%,那麼你的那個擁有width: 128px屬性的元素在1024px寬的顯示器上只會重複顯示4次。佈局

現代瀏覽器中實現縮放的方式無怪乎都是「拉伸」像素。因此,元素的寬度並無從128個像素被修改成256個像素;相反是實際像素被放大了兩倍。形式上,元素仍然是128個CSS像素寬,即便它佔據了256個設備像素的空間。測試

換句話說,放大到200%使一個CSS像素變成爲一個設備像素的四倍。(寬度2倍,高度2倍,總共4倍)網站

一些配圖能夠解釋清楚這個概念。這兒有四個100%縮放比的元素。這兒沒有什麼值得看的;CSS像素與設備像素徹底重疊。ui

csspixels_100

如今讓咱們縮小。CSS像素開始收縮,這意味着如今一個設備像素覆蓋了多個CSS像素。

csspixels_out

若是你進行放大,相反的行爲會發生。CSS像素開始變大,如今一個CSS像素覆蓋了多個設備像素。

csspixels_in

這兒的要點是你只對CSS像素感興趣。這些就是那些控制你的樣式表如何被渲染的像素。

設備像素對你(譯者:指的是開發者)來講基本上沒用。可是對於用戶不同;用戶將會放大或者縮小頁面直到他能舒服的閱讀爲止。不管怎樣,縮放比例對你不會產生影響。瀏覽器將會自動的使你的CSS佈局被拉伸或者被壓縮。

100%縮放

我是以假設縮放比例爲100%來開始這個例子的。是時候須要更加嚴格的來定義一下這個100%了:

在縮放比例100%的狀況下一個CSS像素徹底等於一個設備像素。

100%縮放的概念在接下來的解釋中會很是有用,可是在你的平常工做中你不用過度的擔憂它。在桌面環境上你將會在100%縮放比例的狀況下測試你的站點,但即便用戶放大或者縮小,CSS像素的魔力將會保證你的佈局保持相同的比率。

屏幕尺寸

screen.width/height

  • 意義:用戶屏幕的總體大小。
  • 度量單位:設備像素。
  • 瀏覽器錯誤:IE8以CSS像素對其進行度量,IE7和IE8模式下都有這個問題。

讓咱們看一些實用的度量。咱們將會以screen.widthscreen.height作爲開始。它們包括用戶屏幕的整個寬度和高度。它們的尺寸是以設備像素來進行度量的,由於它們永遠不會變:它們是顯示器的屬性,而不是瀏覽器的。

desktop_screen

Fun! 可是這些信息跟對咱們有什麼用呢?

基本上沒用。用戶的顯示器尺寸對於咱們來講不重要-好吧,除非你想度量它來豐富你的web統計數據庫。

窗口尺寸

window.innerWidth/Height

  • 意義:瀏覽器窗口的總體大小,包括滾動條。
  • 度量單位:CSS像素。
  • 瀏覽器錯誤:IE7不支持。Opera以設備像素進行度量。

相反,你想知道的是瀏覽器窗口的內部尺寸。它告訴了你用戶到底有多少空間能夠用來作CSS佈局。你能夠經過window.innerWidthwindow.innerHeight來獲取這些尺寸。

desktop_inner

很顯然,窗口的內部寬度是以CSS像素進行度量的。你須要知道你的佈局空間中有多少能夠擠進瀏覽器窗口,當用戶放大的時候這個數值會減小。因此若是用戶進行放大操做,那麼在窗口中你能獲取的空間將會變少,window.innerWidth/Height的值也變小了。 (這兒的例外是Opera,當用戶放大的時候window.innerWidth/Height並無減小:它們是以設備像素進行度量的。這個問題在桌面上是比較煩人的,可是就像咱們將要看到的,這在移動設備上倒是很是嚴重的。)

desktop_inner_zoomed

注意度量的寬度和高度是包括滾動條的。它們也被視爲內部窗口的一部分。(這大部分是由於歷史緣由形成的。)

滾動距離

window.pageX/YOffset

  • 意義:頁面滾動的距離。
  • 度量單位:CSS像素。
  • 瀏覽器錯誤:無。

window.pageXOffsetwindow.pageYOffset,包含了文檔水平和垂直方向的滾動距離。因此你能夠知道用戶已經滾動了多少距離。

desktop_page

這些屬性也是以CSS像素進行度量的。你想知道的是文檔已經被滾動了多長距離,無論它是放大仍是縮小的狀態。

理論上,若是用戶向上滾動,而後放大,window.pageX/YOffset將會發生變化。可是,瀏覽器爲了想保持web頁面的連貫,會在用戶縮放的時候保持相同的元素位於可見頁面的頂部。這個機制並不能一直很完美的執行,可是它意味着在實際狀況下window.pageX/YOffset並無真正的更改:被滾動出窗口的CSS像素的數量仍然(大概)是相同的。

desktop_page_zoomed

概念:viewport

在咱們繼續介紹更多的JavaScript屬性以前,咱們必須介紹另外一個概念:viewport。

viewport的功能是用來約束你網站中最頂級包含塊元素(containing block)<html>的。

這聽起來有一點模糊,因此看一個實際的例子。假設你有一個流式佈局,而且你衆多邊欄中的一個具備width: 10%屬性。如今這個邊欄會隨着瀏覽器窗口大小的調整而剛好的放大和收縮。可是這究竟是如何工做的呢?

從技術上來講,發生的事情是邊欄獲取了它父元素寬度的10%。比方說是<body>元素(而且你尚未給它設置過寬度)。因此問題就變成了<body>的寬度是哪一個?

普通狀況下,全部塊級元素使用它們父元素寬度的100%(這兒有一些例外,可是讓咱們如今先忽略它)。因此<body>元素和它的父元素<html>同樣寬。

那麼<html>元素的寬度是多少?它的寬度和瀏覽器窗口寬度同樣。這就是爲何你的那個擁有width: 10%屬性的側邊欄會佔據整個瀏覽器窗口的10%。全部web開發者都很直觀的知道而且在使用它。

你可能不知道的是這個行爲在理論上是如何工做的。理論上,<html>元素的寬度是被viewport的寬度所限制的。<html>元素使用viewport寬度的100%。

viewport,接着,實際上等於瀏覽器窗口:它就是那麼定義的。viewport不是一個HTML結構,因此你不能用CSS來改變它。它在桌面環境下只是擁有瀏覽器窗口的寬度和高度。在移動環境下它會有一些複雜。

後果 Consequences

這個情況會有產生一些異樣的後果。你能夠在這個站點看到這些後果中的一個。滾動到頂部,而後放大兩次或者三次,以後這個站點的內容就從瀏覽器窗口溢出了。

如今滾動到右邊,而後你將會看見站點頂部的藍色邊欄再也不覆蓋一整行了。

desktop_htmlbehaviour

這個行爲是因爲viewport的定義方式而產生的一個後果。我以前給頂部的藍色邊欄設置了width: 100%。什麼的100%?<html>元素的100%,它的寬度和viewport是同樣的,viewport的寬度是和瀏覽器窗口同樣的。

問題是:在100%縮放的狀況下這個工做的很好,如今咱們進行了放大操做,viewport變得比個人站點的整體寬度要小。這對於viewport它自己來講沒什麼影響,內容如今從<html>元素中溢出了,可是那個元素擁有overflow: visible,這意味着溢出的內容在任何狀況下都將會被顯示出來。

可是藍色邊欄並無溢出。我以前給它設置了width: 100%,而且瀏覽器把viewport的寬度賦給了它。它們根本就不在意如今寬度實在是太窄了。

desktop_100percent

文檔寬度?

我真正須要知道的是頁面中所有內容的寬度是多少,包括那些「伸出」的部分。據我所知獲得這個值是不可能的(好吧,除非你去計算頁面上全部元素的寬度和邊距,可是委婉的說,這是容易出錯的)。

我開始相信咱們須要一個我稱其爲「文檔寬度」(document width,很顯然用CSS像素進行度量)的JavaScript屬性對。

desktop_documentwidth

而且若是咱們真的如此時髦,爲何不把這個值引入到CSS中?我將會給個人藍色邊欄設置width: 100%,此值基於文檔寬度,而不是<html>元素的寬度。(可是這個很複雜,而且若是不能實現我也不會感到驚訝。)

瀏覽器廠商們,大家怎麼認爲的?

度量viewport

document.documentElement.clientWidth/Height

  • 意義:Viewport尺寸。
  • 度量單位:CSS像素。
  • 瀏覽器錯誤:無。

你可能想知道viewport的尺寸。它們能夠經過document.documentElement.clientWidth-Height獲得。

desktop_client

若是你瞭解DOM,你應該知道document.documentElement實際上指的是<html>元素:即任何HTML文檔的根元素。能夠說,viewport要比它更高一層;它是包含<html>元素的元素。若是你給<html>元素設置width屬性,那麼這將會產生影響。(我不推薦這麼作,可是那是可行的。)

在那種狀況下document.documentElement.clientWidth-Height給出的仍然是viewport的尺寸,而不是<html>元素的。(這是一個特殊的規則,只對這個元素的這個屬性對產生做用。在任何其餘的狀況下,使用的是元素的實際寬度。)

desktop_client_smallpage

因此document.documentElement.clientWidth-Height一直表明的是viewport的尺寸,無論<html>元素的尺寸是多少。

兩個屬性對

可是難道viewport寬度的尺寸也能夠經過window.innerWidth/Height來提供嗎?怎麼說呢,模棱兩可。

兩個屬性對之間存在着正式區別:document.documentElement.clientWidth-Height並不包含滾動條,可是window.innerWidth/Height包含。這像是雞蛋裏挑骨頭。

事實上兩個屬性對的存在是瀏覽器戰爭的產物。當時Netscape只支持window.innerWidth/Height,IE只支持document.documentElement.clientWidthHeight。從那時起全部其餘瀏覽器開始支持clientWidth/Height,可是IE沒有支持window.innerWidth/Height

在桌面環境上擁有兩個屬性對是有一些累贅的 - 可是就像咱們將要看到的,在移動端這將會獲得祝福。

度量\<html>元素

document.documentElement.offsetWidth/Height

  • 意義:元素(也就是頁面)的尺寸。
  • 度量單位:CSS像素。
  • 瀏覽器錯誤:IE度量的是viewport,而不是元素。

因此clientWidth/Height在全部狀況下都提供viewport的尺寸。可是咱們去哪裏獲取<html>元素自己的尺寸呢?它們存儲在document.documentElement.offsetWidth-Height之中。

desktop_offset

這些屬性可使你以塊級元素的形式訪問<html>元素;若是你設置width,那麼offsetWidth將會表示它。

desktop_offset_smallpage

事件中的座標

pageX/Y, clientX/Y, screenX/Y

  • 意義:見正文。
  • 度量單位:見正文。
  • 瀏覽器錯誤:IE不支持pageX/Y。IE和Opera以CSS像素爲單位計算screenX/Y。

而後是事件中的座標。當一個鼠標事件發生時,有很多於五種屬性對能夠給你提供關於事件位置的信息。對於咱們當前的討論來講它們當中的三種是重要的:

  • pageX/Y提供了相對於<html>元素的以CSS像素度量的座標。

desktop_pageXY

  • clientX/Y提供了相對於viewport的以CSS像素度量的座標。

desktop_clientXY

  • screenX/Y提供了相對於屏幕的以設備像素進行度量的座標。

desktop_screenXY

90%的時間你將會使用pageX/Y;一般狀況下你想知道的是相對於文檔的事件座標。其餘的10%時間你將會使用clientX/Y。你永遠不須要知道事件相對於屏幕的座標。

媒體查詢

媒體查詢

  • 意義:見正文。
  • 度量單位:見正文。
  • 瀏覽器錯誤:IE不支持它們。
    • 若是 device-width/height是以CSS像素進行度量的,那麼Firefox將會使用screen.width/height的值。
    • 若是width/height是以設備像素進行度量的,那麼Safari和Chrome將會使用documentElement.clientWidth/Height的值。

最後,說說關於媒體查詢的事。原理很簡單:你能夠聲明「只在頁面寬度大於,等於或者小於一個特定尺寸的時候纔會被執行」的特殊的CSS規則。好比:

div.sidebar {
    width: 300px;
}

@media all and (max-width: 400px) {
    // styles assigned when width is smaller than 400px;
    div.sidebar {
        width: 100px;
    }

}

當前sidebar是300px寬,除了當寬度小於400px的時候,在那種狀況下sidebar變得100px寬。

問題很顯然:咱們這兒度量的是哪一個寬度?

這兒有兩個對應的媒體查詢:width/heightdevice-width/device-height

  1. width/height使用和documentElement .clientWidth/Height(換句話說就是viewport寬高)同樣的值。它是工做在CSS像素下的。

  2. device-width/device-height使用和screen.width/height(換句話說就是屏幕的寬高)同樣的值。它工做在設備像素下面。

desktop_mediaqueries

你應該使用哪一個?這還用想?固然是width。Web開發者對設備寬度不感興趣;這個是瀏覽器窗口的寬度。

因此在桌面環境下去使用width而去忘記device-width吧。咱們即將看到這個狀況在移動端會更加麻煩。

總結

本文總結了咱們對桌面瀏覽器行爲的探尋。這個系列的第二部分把這些概念指向了移動端,並顯示的指出了與桌面環境上的一些重要區別。

相關文章
相關標籤/搜索