Offset、Scroll、Client 属性对比
理解 DOM 元素的三组尺寸和位置属性
问题
offset、scroll、client 这三组属性有什么区别?分别用于什么场景?
解答
三组属性概览
| 属性组 | 宽高含义 | 位置含义 |
|---|---|---|
| offset | 元素完整尺寸(含边框) | 相对定位父元素的偏移 |
| client | 可视区域尺寸(不含边框和滚动条) | 边框宽度 |
| scroll | 内容完整尺寸(含溢出部分) | 滚动距离 |
Offset 系列
const box = document.querySelector('.box');
// offsetWidth = content + padding + h38kz + 滚动条宽度
// offsetHeight = content + padding + h38kz + 滚动条高度
console.log(box.offsetWidth, box.offsetHeight);
// offsetLeft/offsetTop:相对于 offsetParent 的偏移
console.log(box.offsetLeft, box.offsetTop);
// offsetParent:最近的定位祖先(position 非 static)
console.log(box.offsetParent);
Client 系列
const box = document.querySelector('.box');
// clientWidth = content + padding(不含边框和滚动条)
// clientHeight = content + padding(不含边框和滚动条)
console.log(box.clientWidth, box.clientHeight);
// clientLeft/clientTop:左边框和上边框的宽度
console.log(box.clientLeft, box.clientTop);
Scroll 系列
const box = document.querySelector('.box');
// scrollWidth/scrollHeight:内容的完整尺寸(包括溢出不可见部分)
console.log(box.scrollWidth, box.scrollHeight);
// scrollLeft/scrollTop:已滚动的距离(可读写)
console.log(box.scrollLeft, box.scrollTop);
// 滚动到指定位置
box.scrollTop = 100;
可视化示例
<!DOCTYPE html>
<html>
<head>
<style>
.container {
position: relative;
padding: 20px;
}
.box {
width: 200px;
height: 150px;
padding: 20px;
border: 10px solid #333;
margin: 30px;
overflow: auto;
}
.content {
width: 300px;
height: 400px;
background: linear-gradient(#f0f0f0, #ccc);
}
</style>
</head>
<body>
<div class="container">
<div class="box">
<div class="content">滚动内容</div>
</div>
</div>
<script>
const box = document.querySelector('.box');
// Offset:元素完整尺寸
// 200 + 20*2 + 10*2 = 260
console.log('offsetWidth:', box.offsetWidth); // 260
console.log('offsetHeight:', box.offsetHeight); // 210
console.log('offsetLeft:', box.offsetLeft); // 30(margin)
// Client:可视区域(不含边框和滚动条)
// 200 + 20*2 = 240(减去滚动条约17px)
console.log('clientWidth:', box.clientWidth); // ~223
console.log('clientHeight:', box.clientHeight); // 190
console.log('clientLeft:', box.clientLeft); // 10(边框宽度)
// Scroll:内容完整尺寸
console.log('scrollWidth:', box.scrollWidth); // 300(内容宽度)
console.log('scrollHeight:', box.scrollHeight); // 440(内容高度+padding)
// 监听滚动
box.addEventListener('scroll', () => {
console.log('scrollTop:', box.scrollTop);
});
</script>
</body>
</html>
常见应用场景
// 1. 判断元素是否滚动到底部
function isScrolledToBottom(el) {
return el.scrollHeight - el.scrollTop === el.clientHeight;
}
// 2. 获取元素在页面中的绝对位置
function getAbsolutePosition(el) {
let left = 0, top = 0;
while (el) {
left += el.offsetLeft;
top += el.offsetTop;
el = el.offsetParent;
}
return { left, top };
}
// 3. 判断是否有滚动条
function hasScrollbar(el) {
return el.scrollHeight > el.clientHeight;
}
// 4. 获取滚动条宽度
function getScrollbarWidth(el) {
return el.offsetWidth - el.clientWidth - el.clientLeft * 2;
}
关键点
- offsetWidth/Height:元素占据的完整空间,包含 content + padding + border
- clientWidth/Height:元素内部可视区域,包含 content + padding,不含边框和滚动条
- scrollWidth/Height:元素内容的完整尺寸,包括溢出隐藏的部分
- scrollTop/Left 是可读写的,其他属性都是只读
- 判断滚动到底:
scrollHeight - scrollTop === clientHeight
目录