元素 offset client scroll 相關屬性簡介

qianyin925發表於2019-04-02

一 offset 系列

1.1 定位元素

定位元素(positioned element)是指該元素計算後位置(position)屬性為 relative, absolute, fixed 或 sticky 的一個元素。同時定位屬性又細分為以下幾種:

  • 相對定位元素(relatively positioned element): 指該元素計算後位置(position)屬性為 relative 的元素
  • 絕對定位元素(absolutely positioned element): 指該元素計算後位置(position)屬性為 absolute 或 fixed 的元素
  • 粘性定位元素(stickily positioned element): 指該元素計算後位置(position)屬性為 sticky 的元素

對於絕對定位元素(position 屬性為 absolute 或 fixed 的元素 ), 在未設定 height 和 width 或者為 auto 的情況下,允許通過 top bottom left right 來填充容器可用的空間, 只是 top bottom left right 的參考物件不同而已;

1.2 Element.offsetParent

Element.offsetParent 是一個只讀屬性, 返回當前元素最近的一個父級定位元素。同時又有下列幾種特殊情況:

  • 如果當前元素沒有父級定位元素,則 offsetParent 為最近的標準單元格元素( td 元素)
  • 如果當前元素最近也沒有標準單元格元素,則為 body 元素。(有種說法: 標準模式下為 offsetParent 為 html 元素, quirks 模式下但是經過測試好像都是 body 元素)
  • 在 WebKit 為核心的瀏覽器上,如果元素是隱藏的(style.display='none')或者元素 style.position='fixed',則該元素 offsetParent 為 null
  • 在IE(9)上只有當元素 style.position='fixed' 時 offsetParent 才會返回 null, 即使元素 display = 'none' 也是不會影響返回結果

1.3 Element.offsetLeft && Element.offsetTop

Element.offsetLeft 和 Element.offsetTop 是一個只讀屬性,返回當前**元素邊界(border)**相對於 Element.offsetParent 節點的偏移的畫素值。

  • 示意圖:

元素 offset client scroll 相關屬性簡介

  • 上圖演示程式碼:
<style>
#parent{
  position: relative;
  border: 30px solid red;
  padding: 30px;
  width: 200px;
  height: 200px;
}

#child{
  border: 30px solid blue;
  padding: 30px;
  margin: 20px;
  width: 20px;
  height: 20px;
}
</style>
<div id="parent">
  <div id="child"></div>
</div>
<script>
  const dom = document.getElementById('child');
  console.log(dom.offsetParent);  // <div id="parent"></div>
  console.log(dom.offsetTop);     // 50
</script>
複製程式碼

1.4 Element.offsetWidth && Element.offsetHeight

Element.offsetWidth 和 Element.offsetHeight 是一個只讀屬性,返回一個元素佈局的寬高(元素佈局包括: border、滾動條、padidng、內容塊), 該屬性返回的值為一個四捨五入的整數

  • 示意圖:

元素 offset client scroll 相關屬性簡介

  • 上圖演示程式碼:
<style>
#parent{
  margin: 10px;
  border: 20px solid red;
  padding: 20px;

  width: 100px;
  height: 100px;
  overflow: scroll;
}

#child{
  width: 100%;
  height: 100%;
  background: #eee;
}
</style>

<div id="parent">
  <div id="child"></div>
</div>
<script>
  const dom = document.getElementById('parent');
  console.log(dom.offsetParent);  // <body></body>
  console.log(dom.offsetHeight);  // 180
  console.log(dom.offsetWidth)    // 180
</script>
複製程式碼

1.5 內聯元素下的特殊行為

上文關於 Element offset 系列屬性的描述都是針對塊級元素進行的,至於內聯元素又有一定的區別:

  • 示意圖:

元素 offset client scroll 相關屬性簡介

  • 上圖演示程式碼:
<style>
#parent{
  position: relative;
  width: 200px;
  border: 10px solid red;
}
#Placeholder{
  display: inline-block;
  width: 100px;
}
#child{
  border: 10px solid blue;
  padding: 10px;
}
</style>
<div id="parent">
    <span id="Placeholder">佔位元素</span>
    <span id="child">
      要計算的元素要計算的元素要計算的元素
    </span>
  </div>
<script>
  const dom = document.getElementById('child');
  console.log(dom.offsetParent);
  console.log(dom.offsetTop);     // -12
  console.log(dom.offsetLeft);    // 104
  console.log(dom.offsetWidth);   // 192
  console.log(dom.offsetHeight);  // 102
</script>
複製程式碼

二 client 系列

  • Element.clientTop 和 Element.clientLeft 獲取可視區域的偏移值(實際上就等於元素上下 border 值) 四捨五入(整數)後的結果;
  • Element.clientWidth 和 Element.clientHeight 獲取可視區域(padding + 元素內容區域的寬高,不包含滾動條)的寬高
  • 示意圖:

元素 offset client scroll 相關屬性簡介

  • 上圖演示程式碼:
<style>
  #parent{
    margin: 10px;
    border: 20.5px solid red;
    padding: 20px;

    width: 100px;
    height: 100px;
    overflow: scroll;
  }

  #child{
    width: 100%;
    height: 100%;
    background: #eee;
  }
</style>
<div id="parent">
  <div id="child"></div>
</div>
<script>
  const dom = document.getElementById('parent');
  console.log(dom.clientTop);     // 21
  console.log(dom.clientLeft);    // 21
  console.log(dom.clientWidth);   // 125
  console.log(dom.clientHeight);  // 125
</script>
複製程式碼

三 scroll 系列(用於對可滾動元素進行求值)

3.1 Element.scrollTop && Element.scrollLeft(可寫)

Element.scrollTop 和 Element.scrollLeft 用於獲取或設定元素被捲起的寬高(子元素頂部或左側到當前元素可視區域頂部或左側的距離)

  • 示意圖:以 scrollTop 為例

元素 offset client scroll 相關屬性簡介

  • 上圖演示程式碼:
<style>
  #parent{
    width: 200px;
    height: 200px;
    padding: 50px;
    background: #eee;
    overflow: auto;
  }

  #child {
    height: 400px;
    margin: 50px;
    padding: 50px;
    width: 20px;
    background: #ccc;
  }
</style>
<body>
  <div id="parent">
    <div id="child"></div>
  </div>
</body>
<script>
window.onload = () => {
  const dom = document.getElementById('parent');
  dom.onscroll= () => {
    console.log(dom.scrollTop);
  }
}
</script>
複製程式碼
  • 補充:
    • 對於不可滾動的元素 Element.scrollTop 和 Element.scrollLeft 值為 0
    • 如果給 scrollTop(scrollLeft) 設定的值小於0,那麼 scrollTop(scrollLeft) 的值將變為0。
    • 如果給 scrollTop(scrollLeft) 設定的值大於元素內容最大寬度,那麼 scrollTop(scrollLeft) 的值將被設為元素最大寬度(高度)。

3.2 Element.scrollWidth && Element.scrollHeight

  • Element.scrollWidth 和 Element.scrollHeight 是隻讀屬性, 表示元素可滾動區域的寬高; 實際上又等於 clientHeight/clientWidth + 未顯示在螢幕中內容的寬高;
  • 它們的值等於元素在不使用水平滾動條的情況下適合視口中的所有內容所需的最小寬度。
  • 測量方式與 clientWidth(clientHeight) 相同:它包含元素的內邊距,但不包括邊框,外邊距或垂直滾動條(如果存在)。 它還可以包括偽元素的寬度,例如::before或::after。
  • 如果元素的內容可以適合而不需要水平滾動條,則其 scrollWidth 等於 clientWidth; (最小值為元素的可視區域寬高: clientWidth (clientHeight))
  • 示意圖:以 scrollHeight 為例

元素 offset client scroll 相關屬性簡介

  • 上圖演示程式碼:
<style>
  #parent{
    width: 200px;
    height: 200px;
    padding: 50px;
    background: #eee;
    overflow: auto;
  }

  #child {
    height: 400px;
    margin: 50px;
    padding: 50px;
    width: 20px;
    background: #ccc;
  }
</style>

<body>
  <div id="parent">
    <div id="child"></div>
  </div>
</body>
<script>
window.onload = () => {
  const dom = document.getElementById('parent');
  console.log(dom.scrollHeight); // 700
}
</script>
複製程式碼

補充:

  • 雖然 scrollWidth 計算方式和 scrollHeight 是一樣的, 但是如果在可滾動元素中其子元素使用了 margin-right 則會發生 margin 塌陷等問題, 這時實際計算出的 scrollWidth 會有所不同

相關文章