前言: 在公司移动端项目中,我需要十分频繁的和 DOM 元素的各种 width、height 打交道。但是这里有这么多关于 width 的属性,它们之间的区别到底体现在哪里?这是我刚刚接触移动端项目十分头疼的一个问题。经过几天的查阅,终于搞明白了这几个的不同之处,特来分享。
tips: 本文意指让你自己通过联想记牢这几个属性的区别,而不是单纯地表达它们概念上的不同,故篇幅会较长,还希望读者耐下心细细品读☕️。
一. 前期准备
- 在学习这几个概念之前,我强烈建议你用你喜欢的框架或者工具去简单写一个 元素来更深刻的体会我接下来讲解的内容。不用特别复杂,十分简单的,带有宽度高度的
div
即可。
在页面上的效果如下。
- 接下来你需要进入到开发者页面,选中刚刚我们创造的这个
div
元素。- 然后你需要从右边的选项卡中找到
Properties(dom 属性)
这一项中筛选出带有 width 的几个属性。
接下来你将会频繁的看到这三个属性的变化。二. clientWidth
- 三个属性中我们先对 clientWidth 初步讲解一下。
- 我相信大家初次去 MDN 查阅这个 Css 属性的时候,一定看到过下面这张图。
- 初次看到这张图,感觉它什么都讲了,但是又好像不知道它到底想表达什么。如果你也有这样的疑惑,本文将带你一步步去体会它到底想表达什么。
- 首先切忌死记硬背属性名,我们需要十分明确的知道这个属性名为什么叫
clientWidth
而不是叫小猪佩奇Width
。下面是这个单词的翻译,我认为client
这个单词在这里语境中最佳的翻译应该为---"客户端,用户端"。 - ok,我知道你可能还是有疑惑,别着急,我们一步一步来。经过上面
width
属性搜索结果可知,聪明的你可能已经发现clientWidth
的值不就是我们给这个box
设置的width
的属性值 100 吗? - 是的,对了,但是不完全对。这里更好的说法应该是:“按照我们现在的布局和样式,
clientWidth
的值和width
的值是相等的。”对,只能称作它们的值是相等的,而不能说这两个属性是全等的。 - 那这个
clientWidth
到底该怎么去理解呢?“客户端的宽度?用户端的宽度?”总感觉哪里怪怪的。 - 在这里我先抛出一个我个人认为比较贴切的说法:“
clientWidth
指的是一个 dom 元素中,当前状态下可以被用户即时看到的宽度(理解为可视区域的宽度或许也可以)。 - ”什么意思?假设你现在面前放着一个空的正方体的快递盒子。里面填充了一个大小恰好一模一样的黑色正方体铁块。那么你目前看到的这个铁块的宽度就称作快递盒子(box)的
clientWidth
。 - 现在我们把铁块取出来,得到了一个空的盒子对吧?现在我在盒子周围贴上了一圈10厘米宽的白色泡沫板。然后又找来了一个小一号的,但是又恰好可以一起塞进箱子里的铁块。体现到我们的例子上就是
box
加上了 10px 的border
属性。
然后我们再去Properties
选项卡查看这三个属性。 - 我们发现
clientWidth
的宽度减少了 20px。(我们不是只设置了 10px 吗?怎么一下子减少了 20px 呢?我希望你不要忘了,border
如果没指定具体方向的话,它会在上下左右都设定一份...就像你在快递盒子四个边都塞了一份泡沫板) - 此时你能看到的铁块的宽度就是
clientWidth
,我们好像可以得出一个结论,clientWidth
=width- 左border - 右border
。不对,不能这么早下结论,我们好有影响一个重要属性padding
。那么现在我们给这个盒子添加一个 10px 的padding
测试一下。
好像确实没有影响clientWidth
的宽度,看来我们的这个结论是具有一定的依据的。 - 其实在这里我更想表达的是,我们在理解
padding
这个属性的时候,我们其实可以把它理解为内容区的一部分。因为padding
属性其实也是受到了bg-color(background-color)
的影响,而border
属性是没有受到bg
影响而变为黑色的。这也是为什么padding
没有padding-color
这一属性的原因,因为它本身是被当成了内容区的一一部分,它的颜色是随着内容区(也就是bg-color
) 而改变的原因。 - 这时候我们再去看这张图,这里
padding
为什么有颜色?这其实是MDN
为了更好的去表现出padding
属性而“特意”添加上了不同颜色的。
所以,clientWidth
这一属性更像是描述用户可以直接看到的内容区域。
三. offsetWidth
- 关于
offsetWidth
,其实MDN
有这样一句话能够很完美的表现出它想表达的意思。 它的概念其实非常非常简单,就是在
box-sizing:border
的时候 offsetWidth 其实就等于 dom 元素的 width。不知道你是否遗忘了box-sizing:content
这个标准盒子模型的概念。让我们切换一下box-sizing
的属性,变为content
来看看这个属性值有什么变化。
可以很清楚的看到,在box-sizing:conetent
的时候 offsetWidth= width + 左border + 右border + 左padding + 右padding。这是因为在
content-box
的情况下,我们设置的 dom 元素的宽度其实仅仅只是内容区的宽度。我们设置的 border 和 padding 都是由内容区向外扩张。
在
border-box
下设置的border
和padding
都是由盒子向内部收缩来给 border 或者 padding “腾地方”。- 而
offsetWidth
这个属性是为了表达了盒子的真实物理宽度。所以它的计算方式会根据box-sizing
的不同而不同。 - 在这里你可能会好奇,为什么
clientWidth
也跟着变了?其实根据我们上面讲的:“padding
其实是算作特殊的内容区”来分析,很容易就可以想到clientWidth= 100px+ 10px + 10px
, 所以就等于了 120px。
四. scrollWidth
- 为什么在上面我压根没提这个属性呢?因为这个属性的触发条件很特殊,它只有在特殊的场景下才能体现出和
clientWidth
的区别。(tips:它确实是需要对标clientWidth
的,先不要疑惑,接着往下看你就明白为什么对标的是clientWidth
而不是offsetwidht
了。) - 那这个“特殊场景”指的是什么呢?其实你应该非常熟悉----
overflow
。 ok,那我们怎么创建这个特殊场景呢?其实非常非常简单,你在这个 100px 宽度的盒子里多打几个字就可以。 我们简单设置一下字体的颜色和大小。注意:这里我们已经把
box-sizing
切换成了border-box
,这里为了表现溢出,我们需要设置一个特殊的属性white-space:nowrap
希望大家可以从我博客中学到一些新的知识![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e4ae5bf5960248fba5bae33d8c9bd11e~tplv-k3u1fbpfcp-watermark.image?)- 很清楚的看到,由于我们的字体宽度过大,导致盒子塞不下,但是我们又没有设置溢出场景的处理方法,就导致了现在的样子。
- 我想你已经迫不及待的去
Properties
去查看这几个属性了,但是你有可能一脸疑惑的回来。
什么情况,这scrollWidth
也没变啊!我怀疑你在骗我。 - 其实从
scroll
这个词我们猜或许也能猜到什么。
既然和“滚动”有关,那么现在页面发生滚动了吗?没有,怎么才可以滚动呢?没错overflow-auto
(其它值也一样,只不过auto
方便一点)。 - 设置了
overflow
的处理后,我们现在页面应该是下面这个样子。
我们再去查看这三个属性,你会发现scrollWidth
已经变了。 - 那 390 这个数值是怎么来的呢?这个其实数值要根据你实际项目造成溢出的原因来分析的。但是
scrollWidth
这个属性实际上代表的是“dom元素内容区的真实宽度”。什么意思呢?让我们先把overflow-auto
属性删除,恢复成它原来溢出的样子。 - 然后我们需要通过一些“特殊的手法”去测量一下这个值是体现在哪里。
- 实际上就是文字区域+
padding
区域的宽度。说的直白一点,其实就是内容区(content)。(我再强调一下,你可以把padding
理解为特殊的内容区) - 没错,到这里我想你大概已经明白了,实际上
scrollWidth
代表的就是内容区的真实宽度。在这里我们就需要把clientWidth
拎出来讲一下了。同样是表达内容区宽度的。
1.在内容区没有发生溢出的情况下,scrollWidth = clientWidth 因为它们都是代表内容区的宽度。
2.在内容区发生了溢出,并且设置了 overflow-scroll 之类的属性的情况下,clientWidth
代表dom 当前状态下,实际上展示在可视区域的内容区(content)的宽度。,而 scrollWidth 则代表了真实的 内容区的宽度,包括了那些没有展现在用户面前的,需要滚动才可以看到的内容的宽度。这时候scrollWidth= clientWidth + 溢出的内容区的宽度
。结语
从学习这几个属性的过程中才真正体会到:“看一千遍文档,不如自己动手实践一遍”的道理。还希望大家也可以跟着自己敲一敲,真的不难。与君共勉才是我写这篇文章的初衷~
- 接下来你需要进入到开发者页面,选中刚刚我们创造的这个