你想知道的HTML位置資訊都在這裡了

小兀666發表於2019-05-26

前言

在一次的波紋效果的實現中,因為用到了很多的HTML的位置資訊,之前記得也就一兩個,這次去翻閱MDN後發現,關於HTML的位置資訊竟然後很多引數。於是覺得有必要將這些位置資訊引數的含義做個總結,方便以後參考。

1、Element

Element在是最通用的基類,一個DOM結構中所有的物件都是繼承於它。包括後面介紹的HTMLElement也是繼承於它。所以待會Element的屬性HtmlElement也會擁有。

1.1、clientHeight/clientWidth/clientLeft/clientTop

這四個引數標識的是元素的內部高度/寬度/左邊border的寬度/上面border的寬度。其標識的含義如下圖所示:

clientHeight是元素內部的高度,包含內邊距也就是padding-top/padding-bottom,但是不包含水平滾動條、邊框、和margin。

同理clientWidth也是如此。

clientLeft表示一個元素的左邊框的寬度,有一些相容性的問題可以詳細參考Element.clientLeft

clientTop也是如此。

四個引數的具體取值我們以下面的demo來講解。

我們使用超多的內容去填充div標籤,並且設定了overflow屬性讓其出現水平滾動條或者垂直滾動條,但是這四個引數不為所動,驗證了上面我們剛才說的事實。

1.2、scrollHeight/scrollLeft/scrollLeftMax/scrollTop/scrollTopMax/scrollWidth

這6個引數和滾動相關,在頁面的設計中難免會出現滾動條,想要知道使用者滾到到哪個位置就需要用到上面的某些引數來輔助你的判斷。

scrollHeight標識元素的內容高度,注意和剛才的clientHeight加以區別。當元素不足以展示全部內容的時候使用overflow屬性導致出現不可視的內容區域(也就是出現滾動條)的時候,這些不可視的內容也是包括在內的。在沒有垂直滾動條的情況下,scrollHeight值與元素檢視填充所有內容所需要的最小值clientHeight相同,它包含了元素的padding,但不包含margin。

scrollWidth也是類似。

scrollLeft可以讀取或設定元素滾動條到元素左邊的距離。

Tips

注意如果這個元素的內容排列方向(direction) 是rtl (right-to-left) ,那麼滾動條會位於最右側(內容開始處),並且scrollLeft值為0。此時,當你從右到左拖動滾動條時,scrollLeft會從0變為負數(這個特性在chrome瀏覽器中不存在)

scrollLeftMax返回一個Number表示一個元素橫向滾動條可滾動的最大距離,相容性比較差,屬於新特性,謹慎使用。

scrollTop類似於scrollLeft。

scrollTopMax類似於scrollLeftMax。

我們使用下面demo來說明上面幾個引數的用法。

在demo中我們輸出上面的四個引數(scrollLeftMax/scrollTopMax當前Chrome(v61)不支援)。 結果是:

scrollHeight: 222 scrollLeft: 0 scrollTop: 0 scrollWidth: 336

複製程式碼

當我們把內容減少讓其不要出現滾動條的時候:

可以看到:

scrollHeight: 102 scrollLeft: 0 scrollTop: 0 scrollWidth: 102 clientHeight: 102 clientWidth: 102 clientLeft: 2 clientTop: 2
複製程式碼

clientHeight === scrollHeight/clientWidth === scrollWidth

1.3、getBoundingClientRect()/getClientRects()

這兩個方法也是用來獲取元素的位置以及大小相關的資訊。getClientRects返回的是個陣列,陣列中有很多個類似getBoundingClientRect返回的物件。getBoundingClientRect返回的永遠是最外框框的那個矩形區域相關的座標偏移物件;而getClientRects是多行文字區域的座標偏移集合,在非IE瀏覽器下,只對inline的標籤有反應。

一般getBoundingClientRect方法用的多一點。我們可以很容易獲取某個元素的偏移值。甚至高寬都能很輕鬆的計算出來。

1.3.1、getBoundingClientRect()

getBoundingClientRect返回一個DOMRect物件

DOMRect物件包含了一組用於描述邊框的只讀屬性——left、top、right和bottom,單位為畫素。除了 width 和 height 外的屬性都是相對於視口的左上角位置而言的。

物件裡面的元素如下表(引自DOMRect)

屬性 型別 描述
bottom float Y 軸,相對於視口原點(viewport origin)矩形盒子的底部。只讀。
height float 矩形盒子的高度(等同於 bottom 減 top)。只讀。
left float X 軸,相對於視口原點(viewport origin)矩形盒子的左側。只讀。
right float X 軸,相對於視口原點(viewport origin)矩形盒子的右側。只讀。
top float Y 軸,相對於視口原點(viewport origin)矩形盒子的頂部。只讀。
width float 矩形盒子的寬度(等同於 right 減 left)。只讀。
x float X軸橫座標,矩形盒子左邊相對於視口原點(viewport origin)的距離。只讀。
y float Y軸縱座標,矩形盒子頂部相對於視口原點(viewport origin)的距離。只讀。

在這個demo中我們看到對應的值:

(bottom,height,left,right,top,width,x,y): 114,106,9,115,8,106,9,8}

如何得到這些值呢?我繪製了這麼一張圖片,各個引數的取值由來羅列出來了:

你想知道的HTML位置資訊都在這裡了

需要注意的有以下幾點:

  1. body元素瀏覽器預設給了8px
  2. body元素的margin和test1元素的margin-top發生了margin collapsing(外邊距塌陷),所以得到的top值為8px,y值為8px
  3. right的值左邊會包含元素的margin-left,但是不會包含margin-right,所以其值等於115,同理bottom也是。

1.3.2、getClientRects()

getClientRects返回一個ClientRect物件集合。提供如下的demo來解釋這個方法:

可以在demo中可以看到第一個結果因為文字換行的個數得到集合陣列的長度。每一行文字的位置資訊我們通過列印都可以看到,按照現在顯示是兩行,結果如下:

{"0":{"x":9,"y":5,"width":512.21875,"height":28,"top":5,"right":521.21875,"bottom":33,"left":9},"1":{"x":8,"y":27,"width":424.3125,"height":28,"top":27,"right":432.3125,"bottom":55,"left":8}}
複製程式碼

而div元素的不支援,所以始終得到的結果是一個,這個結果和獲取getBoundingClientRect是一樣的:

{"0":{"x":9,"y":75,"width":526,"height":50,"top":75,"right":535,"bottom":125,"left":9}}
複製程式碼

所以該方法主要用於判斷行內元素是否換行,以及行內元素的每一行的位置偏移

2、HTMLElement

HTMLElement中介紹的是HTMLElement可以標識任何HTML元素。除了繼承Element之外,它同樣有一系列屬於自己的位置引數定義。

2.1、offsetHeight/offsetLeft/offsetParent/offsetTop/offsetWidth

對塊級元素來說,offsetTopoffsetLeftoffsetWidthoffsetHeight描述了元素相對於offsetParent的邊界框。

然而,對於可被截斷到下一行的行內元素(如span),offsetTopoffsetLeft描述的是第一個邊界框的位置(使用Element.getClientRects()來獲取其寬度和高度),而offsetWidthoffsetHeight描述的是邊界框的尺寸(使用 Element.getBoundingClientRect 來獲取其位置)。

  1. HTMLElement.offsetParent是一個只讀屬性,返回一個指向最近的(closest,指包含層級上的最近)包含該元素的定位元素。如果沒有定位的元素,則 offsetParent 為最近的table, table cell根元素(標準模式下為html;quirks模式下為body)。當元素的 style.display 設定為 "none" 時,offsetParent返回null。offsetParent 很有用,因為offsetTopoffsetLeft都是相對於其內邊距邊界的。

  2. offsetHeight獲取元素的畫素高度,包括元素的邊框、內邊距和元素的水平滾動條(如果存在且渲染的話),不包含:before或:after等偽類元素的高度,且是一個整數。這個屬性值會被四捨五入為整數值,如果你需要一個浮點數值,請用element.getBoundingClientRect()

  3. offsetLeft返回當前元素左上角相對於HTMLElement.offsetParent節點的左邊界偏移的畫素值。

  4. offsetWidth是一個只讀屬性,返回一個元素的佈局寬度。一個典型的(譯者注:各瀏覽器的offsetWidth可能有所不同)offsetWidth是測量包含元素的邊框(border)、水平線上的內邊距(padding)、豎直方向滾動條(scrollbar)(如果存在的話)、以及CSS設定的寬度(width)的值。

  5. offsetTop為只讀屬性,它返回當前元素相對於其 offsetParent 元素的頂部的距離

其測試的demo如下:

3、事件中關於位置的資訊

當我們使用click事件或者touch事件的時候也同樣會涉及到位置資訊。Event包含了很多事件的定義,目前我們只關注MouseEventTouchEvent

3.1、MouseEvent

滑鼠點選事件,該事件介面可由這些事件觸發:click/dbclick/mouseup/mousedown

MouseEvent繼承自UIEvent,UIEvent繼承自Event

該事件介面我們關注三個引數:button/clientX/clientY/offsetX/offsetY/pageX/pageY/screenX/screenY。它們分別對應的資訊是:

  1. button標識哪種按鈕被按了,一般有以下5種型別: 0: 標識主按鈕觸發的,一般指的是左邊按鈕或者是未初始化的狀態 1: 輔助按鈕觸發的,一般指的是滾輪按鈕或者是中間的按個按鈕(如果存在的話) 2: 次級按鈕觸發的,一般指的是右邊按鈕 3: 第四個按鈕,一般指的是瀏覽器的返回按鈕 4: 第五個按鈕,一般指的是瀏覽器的前進按鈕

  2. clientX 是隻讀屬性, 它提供事件發生時的應用客戶端區域的水平座標 (與頁面座標不同)。例如,不論頁面是否有水平滾動,當你點選客戶端區域的左上角時,滑鼠事件的 clientX 值都將為 0 。最初這個屬性被定義為長整型(long integer),如今CSSOM檢視模組將其重新定義為雙精度浮點數(double float),clientY類似。

  3. movementX 是隻讀屬性,它提供了當前事件和上一個mousemove事件之間滑鼠在水平方向上的移動值。換句話說,這個值是這樣計算的 : currentEvent.movementX = currentEvent.screenX - previousEvent.screenX.movementY類似。

  4. offsetX是滑鼠點選的位置相對於目標節點內邊位置的X座標,offsetY類似。

  5. pageX 是一個由MouseEvent介面返回的相對於整個文件的x(水平)的座標。這個屬性考慮任何頁面的水平方向上的滾動。 起初這個屬性被定義為長整型。 CSSOM 檢視模組將它重新定位為雙浮點數型別。

  6. screenX是隻讀屬性,標識滑鼠點選的位置在全域性座標中橫軸的偏移位置。screenY類似。

  7. x屬性是clientX的簡寫,值等於clientX.

3.2、TouchEvent

觸控事件,常用於移動端裝置。一次觸控可以產生一個Touch物件,TouchEvent中的touches代表了所有當前接觸觸控平面的觸點的 Touch物件。這次我們著重關注touches這個屬性。

touches是一個集合,集合裡面的物件包含的屬性大致和MouseEvent的是一樣。但是也有些特有的屬性:

  1. identifier: 此 Touch 物件的唯一識別符號. 一次觸控動作(我們值的是手指的觸控)在平面上移動的整個過程中, 該識別符號不變. 可以根據它來判斷跟蹤的是否是同一次觸控過程.

  2. radiusX標識能夠包圍使用者和觸控平面的接觸面的最小橢圓的水平軸(X軸)半徑. 這個值的單位和 screenX 相同.radiusY類似

  3. rotationAngle: 它是這樣一個角度值:由radiusX 和 radiusY 描述的正方向的橢圓,需要通過順時針旋轉這個角度值,才能最精確地覆蓋住使用者和觸控平面的接觸面.

  4. force:手指擠壓觸控平面的壓力大小, 從0.0(沒有壓力)到1.0(最大壓力)的浮點數.取決於移動裝置的支援。

  5. target是觸控最開始觸控到的元素。哪怕在觸點移動過程中, 觸點的位置已經離開了這個元素的有效互動區域, 或者這個元素已經被從文件中移除. 需要注意的是, 如果這個元素在觸控過程中被移除, 這個事件仍然會指向它, 但是不會再冒泡這個事件到 window 或 document 物件. 因此, 如果有元素在觸控過程中可能被移除, 最佳實踐是將觸控事件的監聽器繫結到這個元素本身, 防止元素被移除後, 無法再從它的上一級元素上偵測到從該元素冒泡的事件

二者事件的demo如下:

要檢視touchEvent的位置資訊需要把該demo在Chrome上調為移動端模式,點選一下框即可得到點選的位置資訊。

4、最後的總結

屬性 型別 說明
clientHeight/clientWidth float 元素內部的高度,只包含內邊距也就是padding-top/padding-bottom,width類似
clientLeft/clientTop float 元素的左邊框/上邊框的寬度
scrollHeight/scrollWidth float 標識元素的內容高度內容寬度
scrollLeft/scrollTop float 可以讀取或設定元素滾動條到元素左邊/上邊的距離
getBoundingClientRect().bottom/top float Y 軸,相對於視口原點(viewport origin)矩形盒子的底部/頂部。
getBoundingClientRect().height/width float 矩形盒子的高度/寬度(等同於 bottom 減 top/right 減 left)。
getBoundingClientRect().left/right float X 軸,相對於視口原點(viewport origin)矩形盒子的左/右側。
getBoundingClientRect().x/y float X/Y軸橫座標,矩形盒子左邊/頂部相對於視口原點(viewport origin)的距離。只讀。
offsetHeight/offsetWidth int 元素的畫素高度,包括元素的邊框、內邊距和元素的水平滾動條(如果存在且渲染的話),不包含:before或:after等偽類元素的高度
offsetLeft/offsetTop int 當前元素相對於其 offsetParent 元素的頂部的距離/左上角相對於HTMLElement.offsetParent節點的左邊界偏移的畫素值
clientX/clientY long 滑鼠點選事件發生時的應用客戶端區域的水平座標 (與頁面座標不同)
movementX/movementY float 當前事件和上一個mousemove事件之間滑鼠在水平/垂直方向上的移動值
offsetX/offsetY float 滑鼠點選的位置相對於目標節點內邊位置的X/Y座標
pageX/pageY float 一個由MouseEvent介面返回的相對於整個文件的x/y(水平/垂直)的座標
screenX/screenY long 標識滑鼠點選的位置在全域性(螢幕)座標中橫軸/縱軸的偏移位置
radiusX/radiusY float 能夠包圍使用者和觸控平面的接觸面的最小橢圓的水平/縱軸軸(X/Y軸)半徑

Tips:

  1. 帶有client字眼的屬性一般是衡量屬性自身的尺寸(不包含不可見區域)
  2. 帶有offset字眼的屬性一般指的是元素相對於某個參照物的位置資訊
  3. 帶有page字眼的屬性一般指的是元素相對於整個檢視包括滾動未見的區域的位置資訊
  4. 帶有screen字眼的屬性一般指的是元素相對於檢視不包括不可見區域的位置資訊

參考

  1. TouchEvent.touches
  2. Touch

相關文章