前言
大家好,我是抹茶。 长期以来一直没有彻底弄懂clientWidth、offsetWidth、scrollWidth的具体含义,查资料都总是遇到每个字我都认识,但是组合在一起不知道他想表达什么的困境。所以我决定不嗑资料了,而是自己写测试demo,去推导和理解各个字段的含义。
术语解释
因为形如width + paddingLeft + paddingRight的方式要记的信息点太多,所以笔者直接采用content-box、padding-box、border-box、margin-box的方式进行记忆。
content-box
content-box为box-sizing:content-box时width占据的大小
padding-box
padding-box为padding及以内包裹的内容的大小
border-box
border-box为border及以内包裹的内容的大小
margin-box
margin-box为margin及以内包裹的内容的大小
测试过程
1.clientWidth、offsetWidth、scrollWidth
- div没有横向滚动条的时候
offsetWidth最大,为盒子整体占据的屏幕大小(不含margin)
clientWidth和scrollWidth为padding-box的大小
测试条件:
- 屏幕宽度:1016px
- 父级盒子的margin-left:8px,margin-right:8px;
测试结果:
- 有竖向滚动条的:
- clientWidth: 965
- offsetWidth: 1000
- scrollWidth: 965
- 无竖向滚动条的:
- clientWidth: 980
- offsetWidth: 1000
- scrollWidth: 980
对比可得,clientWidth和scrollWidth不包含滚动条的宽度(980和965之间的差距就是竖向滚动条的宽度),clientWidth和scrollWidth为padding-box的宽度(根据盒模型宽度推断得出)。
offsetWidth为border-box的宽度 + 竖向滚动条的宽度。
- div有横向滚动条的时候
有溢出的时候,scrollWidth最大,为盒子内容的最小宽度。
没有溢出时保持offsetWidth是border-box的宽度,clientWidth和scrollWidth为padding-box的宽度
2.clientHeight、offsetHeight、scrollHeight
- 测试条件
height:150px;
padding:20px;
border:10px solid xxx;
- 测试结果
-
有竖向滚动条时
scrollHeight最大,为内容的高度 -
没有滚动条时
offsetHeight最大,为border-box的高度,clientHeight和scrollHeight为padding-box的高度
-
3.clientLeft、offsetLeft
测试条件
// 父级盒子
padding;20px;
border:10px solid xxx;
//子盒子
padding:10px;
border: 5px solid xxx;
// 浮动元素子盒子
padding;10px;
border:6px solid xxx;
结合图中信息可得,clientLeft为div盒子的border-left的宽度,offsetWidth为到屏幕最左边的距离。
4.clientTop、offsetTop
测试条件
// 父级盒子
padding;20px;
border:10px solid xxx;
//子盒子
padding:10px;
border: 5px solid xxx;
// 浮动元素子盒子
padding;10px;
border:6px solid xxx;
从图中信息可得,clientTop是border-top的宽度,offsetTop是到距离(0,0)的高度。
5. scrollLeft和scrollRight
scrollLeft为div出现横向滚动条时,滚动条到左边的距离。
scrollRight为div出现竖向滚动条时,滚动条到上边的距离。
在没有出现滚动条的时候,或者滚动条移动到最左边和最上边,scrollLeft和scrollTop都为0。
总结
首先,clientXXX相关的宽高指的是padding-box的宽高,而offsetXXX相关的宽高指的是border-box的宽高+对应方向的滚动条的宽度。
scrollWidth和scrollHeight根据出现滚动条与否差别较大,没有出现滚动条的时候scrollWidth == clientWidth,scrollHeight == clientHeight,在出现滚动条的时候,他们等于内容的最小宽度。
offsetLeft和offsetTop指的是到左上角(0,0)的距离,而clientLeft和clientTop分别指的是左边和右边的border的宽度。
scrollLeft和scrollTop表示的是滚动条的移动距离,如果没有滚动条,或者滚动条位于最左边或最上边时,scrollLeft和scroll都为0。
测试源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
html,
body {
margin: 0;
box-sizing: content-box;
}
/* 滚动盒子 */
.scroll-box {
height: 150px;
overflow: auto;
padding: 20px;
margin: 8px;
border: 10px solid rgb(56, 18, 179);
}
.scroll-item {
width: 600px;
height: 200px;
padding: 10px;
border: 5px solid purple;
background-color: skyblue;
}
/* 浮动盒子 */
.float-box {
margin: 8px;
margin-top:20px;
height: 150px;
padding: 20px;
border: 10px solid palegreen;
}
.float-item {
width: 100px;
height: 100px;
padding:5px;
border:6px solid purple;
float: left;
background-color: rgb(63, 224, 224);
}
/* 绝对定位 */
.relative-box{
position:relative;
margin: 8px;
margin-top:20px;
height:150px;
padding:20px;
border: 10px solid purple;
}
.absolute-item{
position:relative;
margin-top:20px;
width:50%;
height:50%;
padding:10px;
border: 5px solid skyblue;
}
.flex-box{
display: flex;
margin: 8px;
margin-top:20px;
height:150px;
padding:20px;
border:10px solid orange;
justify-content: space-between;
align-items: center;
}
.flex-item{
width:100px;
height:100px;
padding:10px;
border:5px solid seagreen;
}
</style>
</head>
<body>
<div class="scroll-box" id="scroll-parent" onclick="computedStyle('scroll-parent','滚动布局的父元素')">
<div class="scroll-item" id="scroll-child" onclick="computedStyle('scroll-child','滚动布局的子元素',event)">滚动布局</div>
</div>
<div class="float-box" id="float-parent" onclick="computedStyle('float-parent','浮动布局的父元素')">
<div class="float-item" id="float-child" onclick="computedStyle('float-child','浮动布局的子元素',event)">浮动元素</div>
</div>
<div class="relative-box" id="relative-parent" onclick="computedStyle('relative-parent','绝对定位的父元素')">
<div class="absolute-item" id="absolute-child" onclick="computedStyle('absolute-child','绝对定位的子元素',event)">绝对定位</div>
</div>
<div class="flex-box" id="flex-parent" onclick="computedStyle('flex-parent','浮动布局的父元素')">
<div class="flex-item" id="flex-child-1" onclick="computedStyle('flex-child-1','flex一号盒子',event)">flex一号盒子</div>
<div class="flex-item" id="flex-child-2" onclick="computedStyle('flex-child-2','flex二号盒子',event)">flex二号盒子</div>
</div>
</body>
<script type="text/javascript">
// 如果你需要处理多个元素,可以定义一个函数来获取这些属性
function getElementProperties(id) {
const element = document.getElementById(id);
if(!element) {
console.log('找不到,id:'+id);
return;
}
// 获取元素的尺寸和位置
const offsetWidth = element.offsetWidth;
const offsetHeight = element.offsetHeight;
const offsetTop = element.offsetTop;
const offsetBottom = element.offsetBottom;
const offsetLeft = element.offsetLeft;
const offsetRight = element.offsetRight;
// 获取滚动相关属性
const scrollWidth = element.scrollWidth;
const scrollHeight = element.scrollHeight;
const scrollTop = element.scrollTop;
const scrollBottom = element.scrollBottom;
const scrollLeft = element.scrollLeft;
const scrollRight = element.scrollRight;
// 获取元素边框和客户区大小
const clientTop = element.clientTop;
const clientBottom = element.clientBottom;
const clientLeft = element.clientLeft;
const clientRight = element.clientRight;
const clientWidth = element.clientWidth;
const clientHeight = element.clientHeight;
return {
// offset: {
// offsetWidth,
// offsetHeight,
// offsetTop,
// offsetBottom,
// offsetLeft,
// offsetRight,
// },
// client: {
// clientWidth,
// clientHeight,
// clientTop,
// clientBottom,
// clientLeft,
// clientRight,
// },
// scroll: {
// scrollWidth,
// scrollHeight,
// scrollTop,
// scrollBottom,
// scrollLeft,
// scrollRight,
// },
// width: {
// offsetWidth,
// clientWidth,
// scrollWidth,
// },
// height: {
// offsetHeight,
// clientHeight,
// scrollHeight,
// },
// top: {
// offsetTop,
// clientTop,
// scrollTop,
// },
// bottom:{
// offsetBottom,
// scrollBottom,
// clientBottom
// },
// left: {
// offsetLeft,
// clientLeft,
// scrollLeft,
// },
right: {
offsetRight,
clientRight,
scrollRight,
},
};
}
function computedStyle(id,name,event) {
// 使用该函数
const properties = getElementProperties(id);
console.group(name);
console.log(properties);
console.groupEnd();
console.log('\n');
if (event) {
event.stopPropagation(); // 阻止事件冒泡
}
}
</script>
</html>