章
目
录
很多前端开发朋友对于理解DOM元素的尺寸以及相关的盒模型、宽高属性仍有不足,但它们直接影响页面的布局和显示效果,今天就来深入探讨一下这些知识。
一、深入理解两种盒模型
在CSS中,box-sizing
属性用于控制盒模型的类型,主要有两种盒模型:标准盒模型和IE盒模型。
(一)标准盒模型(content-box)
在标准盒模型下,width
和height
仅仅表示元素内容区域的尺寸。假设我们设置了如下样式:
.box {
width: 200px;
height: 100px;
padding: 20px;
border: 10px solid;
margin: 30px;
}
用图形来表示的话,就是这样:
+----------------------------------------+
| Margin (30px) |
| +----------------------------------+ |
| | Border (10px) | |
| | +----------------------------+ | |
| | | Padding (20px) | | |
| | | +----------------------+ | | |
| | | | Content (200px) | | | |
| | | +----------------------+ | | |
| | | | | |
| | +----------------------------+ | |
| | | |
| +----------------------------------+ |
+----------------------------------------+
从这个图中可以清晰地看到,计算元素的总宽度时,需要把内容宽度、左右padding、左右border以及左右margin都加起来,即总宽度 = 200 + 20×2 + 10×2 + 30×2 = 320px。
(二)IE盒模型(border-box)
IE盒模型(border-box
)和标准盒模型有所不同,这里的width
和height
表示的是内容、padding和border的总和。还是以上面的样式为例,用图形表示如下:
+----------------------------------------+
| Margin (30px) |
| +----------------------------------+ |
| | Border (10px) + Padding (20px) | |
| | +----------------------------+ | |
| | | Content (实际: 140px) | | |
| | | (200 - 20*2 - 10*2 = 140) | | |
| | +----------------------------+ | |
| | | |
| +----------------------------------+ |
+----------------------------------------+
在IE盒模型下,计算总宽度时,只需要把设置的width
和左右margin
相加就行,所以总宽度 = 200 + 30×2 = 260px ,这里内容的实际宽度则是通过设置的width
减去左右padding
和左右border
得到的,即200 – 20×2 – 10×2 = 140px。
二、DOM元素的宽高属性详解
了解了盒模型之后,接下来看看与DOM元素宽高相关的几个属性。
(一)offsetWidth / offsetHeight
这个属性包含了内容的width/height
、padding
以及border
,但不包含margin
。以之前设置的样式为例:
- 在
content-box
盒模型下,offsetWidth
的计算方式为:内容宽度 + 左右padding
+ 左右border
,即200 + 20×2 + 10×2 = 260px。 - 在
border-box
盒模型下,offsetWidth
就等于设置的width
,也就是200px。
(二)clientWidth / clientHeight
clientWidth
和clientHeight
属性包含内容的width/height
和padding
,但不包含border
和margin
。同样以之前的样式为例:
- 在
content-box
盒模型下,clientWidth
= 内容宽度 + 左右padding
,即200 + 20×2 = 240px。 - 在
border-box
盒模型下,clientWidth
= 设置的width
– 左右border
,即200 – 10×2 = 180px。
(三)getBoundingClientRect
getBoundingClientRect
方法返回的width
和height
等于 (内容 + padding
+ border
) × transform
缩放系数,并且这个宽高与盒模型的设置无关。它的主要作用是返回元素相对于视口的精确几何信息,返回值是一个DOMRect
对象,包含8个属性:
{
x: // 元素左上角X坐标(等同left)
y: // 元素左上角Y坐标(等同top)
left: // 元素左侧到视口左侧的距离
top: // 元素顶部到视口顶部的距离
right: // 元素右侧到视口左侧的距离
bottom: // 元素底部到视口顶部的距离
width: // 元素的实际渲染宽度(含transform)
height: // 元素的实际渲染高度(含transform)
}
- 坐标系示意图:视口的左上角坐标为(0,0),X轴向右延伸,Y轴向下延伸。元素的左上角坐标为(left, top) ,并且满足
rect.right === rect.left + rect.width
和rect.bottom === rect.top + rect.height
这样的关系。 - 性能注意事项:在使用
getBoundingClientRect
方法时,要注意性能问题。频繁调用这个方法会强制同步布局,导致性能下降。所以最好批量读取相关属性,例如:
// (触发两次重排)
const width = el.getBoundingClientRect().width;
const height = el.getBoundingClientRect().height;
// (单次重排)
const rect = el.getBoundingClientRect();
const width = rect.width;
const height = rect.height;
后面这种方式连续读取多个属性,只会触发一次重排,能有效提升性能。
(四)scroll相关属性和方法
- scrollHeight & scrollWidth:
scrollHeight
等于内容的实际高度加上padding
,scrollWidth
等于内容的实际宽度加上padding
。比如下面这个例子:
<div id="container" style="height:200px; overflow-y:scroll">
<div style="height:800px; padding:20px"></div>
</div>
<script>
console.log(container.scrollHeight); // 800 + 20*2 = 840
// 如果设置overflow-y:hidden,container.scrollHeight = 800 + 20 = 820
</script>
- scrollTop & scrollLeft:
scrollTop
表示元素内容向上滚动的距离,scrollLeft
表示元素内容向左滚动的距离。判断元素是否滚动到底部,可以通过element.scrollTop >= scrollHeight - clientHeight
这个式子来判断,同理,判断是否滚动到最右侧,可以用element.scrollLeft >= scrollWidth - clientWidth
。 - scrollTo方法:使用
scrollTo
方法可以实现平滑滚动效果,比如下面这样:
// 原生平滑滚动
element.scrollTo({
top: 500,
behavior:'smooth'
});
- scrollTopMax / scrollLeftMax:目前只有火狐浏览器支持这两个属性。
scrollTopMax
表示最大可滚动距离,即scrollHeight - clientHeight
,常用于检测元素是否滚动到底部;scrollLeftMax
表示最大水平滚动距离,即scrollWidth - clientWidth
,可用于横向滚动限制检测。兼容性方面,Chrome、Safari、Edge和IE都不支持这两个属性,只有Firefox 44及以上版本支持 。
通过对DOM元素盒模型和各种宽高属性的详细介绍,希望大家能在前端开发中更准确地把握页面布局,避免因尺寸计算错误导致的显示问题。
兼容性对照表
属性/方法 | Chrome | Firefox | Safari | Edge | IE |
---|---|---|---|---|---|
scrollTopMax | ❌ | ✅ 44+ | ❌ | ❌ | ❌ |