背景
身為一個前端工程師,每次在做關于滾動或者定位之類的交互時,或多或少都會用到offset、scroll之類的元素屬性值來計算距離,但是每次都是現用現百度,從來沒有真正系統地弄明白其中的原理及用法;在馬上十一國慶假期以及項目壓力較小的情況下,特作此篇總結以彌補相關知識的缺失
offset相關
以offset開頭的屬性有5個,分別是:offsetParent
、offsetWidth
、offsetHeight
、offsetTop
以及offsetLeft
,下面我們來一一了解它們
1.offsetParent
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>offsetParent</title>
<style>
</style>
</head>
<body>
<!--1.除了瀏覽器默認的,我們沒有設置任何樣式-->
<div id="outer">
<div id="inner">
我是div
</div>
</div>
<script>
// 2.我們看看id="inner"元素的offsetParent是哪一個
var inner = document.getElementById('inner')
console.log(inner.offsetParent)
</script>
</body>
</html>
從控制臺我們得到inner的offsetParent是body元素,那么就有問題了“inner的父元素是outer啊,但為什么offsetParent不是它?”,那是因為元素的offsetParent是距離它最近的一個具有定位的父輩元素,這里“具有定位”4個字很重要,如果你懷疑這個結論,那我們就再往下看
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>offsetParent</title>
<style>
/*這里我們給outer一個相對定位*/
#outer {
position: relative;
}
</style>
</head>
<body>
<!--1.除了瀏覽器默認的,我們沒有設置任何樣式-->
<div id="outer">
<div id="inner">
我是div
</div>
</div>
<script>
// 2.我們看看id="inner"元素的offsetParent是哪一個
var inner = document.getElementById('inner')
console.log(inner.offsetParent)
</script>
</body>
</html>
看出不同了嗎,outer有了相對定位,結果呢?
很明顯,inner在一層層向上查找時,找到outer的時候,發現outer有定位(inner不管outer具體是什么定位,只要有定位就好,除了position: static
),那么關于element.offsetParent
,我們可以有以下結論“元素的offsetParent是距離該元素最近的且具有定位的父輩元素,如果沒有符合條件的父輩元素,那么body就是它的offsetParent”
2.offsetWidth與offsetHeight
以offsetWidth為例,offsetWidth=width+padding*2+border*2+[橫向滾動條width]
,這里滾動條的高度是否計算在offsetWidth內,各瀏覽器在具體實現上存在差異,例如chrome就沒有將它計算在內;說到這,何為offsetWidth與offsetHeight?不著急,看看下面的代碼示例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>offsetWidth</title>
<style>
#outer {
position: relative;
width: 360px;
height: 300px;
padding: 40px;
overflow: scroll;
border: 20px solid #ff552e;
}
</style>
</head>
<body>
<div id="outer">
我是outer
</div>
<script>
var outer = document.getElementById('outer')
console.log('offsetWidth:' + outer.offsetWidth)
</script>
</body>
</html>
可以注意到,我們設置outer的width是360px,但在頁面中,outer的實際寬度是480px,這是因為offsetWidth是元素的布局寬度,而非樣式寬度,即當元素真正渲染到頁面后的寬度,我們在屏幕上看到的這個寬度就是width+padding*2+border*2
后的結果值,所以,關于offsetWidth的結論是:“offsetWidth是元素渲染到頁面后的實際寬度尺寸,同理,offsetHeight就是元素渲染到頁面后的實際高度尺寸”
3.offsetTop與offsetLeft
關于這兩個屬性,我想聰明的小伙伴已經猜到了,它們就是“元素與它的offsetParent的上邊界與左邊界的距離”
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>offsetTop&offsetLeft</title>
<style>
#outer {
position: relative;
width: 360px;
height: 300px;
/*使用padding讓outer與inner產生距離*/
padding-top: 20px;
padding-left: 10px;
border: 1px solid #666;
}
#inner {
height: 100px;
border: 1px solid #ff552e;
}
</style>
</head>
<body>
<div id="outer">
<div id="inner">
我是inner
</div>
</div>
<script>
var inner = document.getElementById('inner')
console.log('offsetTop:' + inner.offsetTop)
console.log('offsetLeft:' + inner.offsetLeft)
</script>
</body>
</html>
那么我們再擴展一下,如果outer不具有定位呢,offsetTop與offsetLeft會是什么?當然是inner距離body的上邊界與左邊界的值了
scroll相關
1.scrollWidth
一個元素要想在scrollWidth有值,那么它要滿足至少以下兩點:
1.元素要有寬度,并且寬度是生效的(如果你給一個行內元素設置width,寬度是不生效的)
2.元素的內部要有一個子元素,或者文本;子元素的width要大于該元素;如果是文本,那么文本在不換行的情況下要超出該元素的水平邊界。
總結一句就是:元素必須是可滾動的
看下面示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>scrollWidth</title>
<style>
#outer {
position: relative;
/*注意此處的值*/
width: 360px;
height: 300px;
overflow: scroll;
border: 1px solid #666;
}
#inner {
/*注意此處的值*/
width: 600px;
height: 100px;
/*padding: 10px;*/
border: 1px solid #ff552e;
}
</style>
</head>
<body>
<div id="outer">
<div id="inner">
我是inner
</div>
</div>
<script>
var outer = document.getElementById('outer')
console.log('scrollWidth:' + outer.scrollWidth)
</script>
</body>
</html>
細心的童鞋注意到outer.scrollWidth不等于outer的寬度,而且inner的寬度,更準確的說是inner.offsetWidth,不信你可以把inner的padding注釋打開看看O(∩_∩)O哈!
2.scrollHeight
同上,原理相同
3.scrollTop&scrollLeft
scrollTop與scrollLeft就是當可滾動的元素發生滾動時,里面的子元素分別從上邊界和左邊界出去了多少距離
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>scrollTop&scrollLeft</title>
<style>
#outer {
position: relative;
width: 360px;
height: 300px;
overflow: scroll;
border: 1px solid #666;
}
#inner {
/*inner的寬高都大于outer,所以outer水平垂直滾動條都會出現*/
width: 600px;
height: 600px;
padding: 10px;
border: 1px solid #ff552e;
}
</style>
</head>
<body>
<div id="outer">
<div id="inner">
我是inner
</div>
</div>
<script>
var outer = document.getElementById('outer')
// 未滾動
console.log('未滾動')
console.log('scrollTop:' + outer.scrollTop)
console.log('scrollLeft:' + outer.scrollLeft)
// 手動滾動,然后再次輸出scrollTop
setTimeout(function () {
console.log('已滾動')
console.log('scrollTop:' + outer.scrollTop)
console.log('scrollLeft:' + outer.scrollLeft)
}, 2000)
</script>
</body>
</html>
結語
以上就是關于offset和scroll的總結,知識點并不深,但卻可以對相關知識加深理解,如有錯誤之處,歡迎指正