Blog
Blog copied to clipboard
CSS 世界 —— 盒尺寸四大家族
盒尺寸四大家族
替换元素
通过修改某个属性值呈现的内容就可以被替换的元素就被称为 “替换元素”。<img>、<object>、<vedio>、<iframe>、<textarea>、<input> 等都是典型的替换元素
替换元素除了内容可替换以外,还有哪些特性:
-
内容的外观不受页面上的 CSS 的影响
-
有自己的尺寸:在不设置尺寸的时候,这些元素会有一个默认的尺寸(300 * 150),如:
<video>、<canvas>、<iframe>。<img>图片默认展示的就是图片的原始尺寸。 -
在很多 CSS 属性上有自己的一套表现规则。比较有代表性的就是
vertical-align属性。对于字符而言,vertical-align的默认值就是baseline,也就是字母 “x” 的下边缘。但是,对于替换元素而言就不一样了。对于图片来说vertical-align的默认值就是图片的下边缘。
替换元素的尺寸计算规则
可以将替换元素的尺寸从内到外分为:“固有尺寸”、“HTML尺寸”、“CSS尺寸”
-
固有尺寸:指的就是替换内容原本的尺寸。例如,图片、视频作为一个单独的文件存在的时候,都有着自己的宽度和高度,这个宽度和高度就是“固有尺寸”
-
HTML尺寸:一些替换元素存在
width和height的HTML属性,例如<img>和<canvas>元素。这个称为HTML尺寸 -
CSS尺寸:指的是可以通过 CSS 的
width和height或者max-width/min-width和max-height/min-height设置元素的尺寸。这种称为 CSS 尺寸
计算规则
- 没有 “CSS尺寸” 和 “HTML尺寸” 时,则使用 ”固有尺寸“ 或者 默认尺寸(300 * 150)
- 没有 ”CSS尺寸“,则使用 “HTML尺寸”
- 如果有 ”CSS尺寸“,则使用 ”CSS尺寸“
如果 ”固有尺寸“ 含有固有的宽度比例,同时仅设置了宽度或者仅设置了高度,则元素依然按照固有比例宽高显示
padding
<div style="height: 32px; line-height: 32px; background: #444">
xxxx<span style="background: #999; padding: 20px 0; border: 5px solid #fff">我是谁</span>xxxx
</div>
<div style="height: 32px; line-height: 32px; background: #555">
xxxx的是非得失丰富的水分是我的
</div>
先看看上面这个 demo,可以看出来,对于内联元素来说,padding 和 border 对内联元素的文字对齐没有影响。(其实内联元素的 padding/border 不计算在行框盒子的高度内)
注意:padding 不能出现负值
padding 的百分比值
-
块级元素的
padding的百分比值无论是水平方向和垂直方向都是相对于宽度进行计算的 -
内联元素的
padding的计算规则就有一点点的差异了- 同样相对于 宽度进行计算
- 默认的高度和宽度细节有差异
- padding 会断行,简单说就是,如果内联元素出现换行时,每一行都会有 padding ,这个地方和块级元素是有差异的。看看下面的这个 demo,就知道了
<div style="width: 100px; border: 2px dashed #444">
<span style="background: #999; padding: 50% 0;">我是谁我是谁我是谁我是谁</span>
</div>
HTML标签内置的 padding
-
<ol>|<ul>列表内置padding-left,但是单位不是 px,而是 em。 -
表单元素内置的
padding -
<input>、<textarea>输入框内部内置padding -
<button>按钮内置padding -
部分浏览器
<select>下拉内置padding -
<radio>、<checkbox>单选框和复选框无内置padding
同背景属性结合绘制特殊的图形
<div style="height: 300px; background: #ccc; margin: 20px">
<div class="circle"></div>
<div class="three-line"></div>
<div class="triangle"></div>
</div>
.circle {
width: 20px;
height: 20px;
padding: 5px;
background: #fff;
background-clip: content-box;
border: 2px solid #fff;
border-radius: 50%;
}
.three-line {
width: 20px;
height: 25px;
border: 3px solid #fff;
border-left-width: 0;
border-right-width: 0;
padding: 8px 0;
background: #fff;
background-clip: content-box;
box-sizing: border-box;
}
.triangle {
display: inline-block;
background: transparent;
border: 10px solid transparent;
border-top-color: #333;
}
margin 与元素尺寸以及相关布局
先介绍几个概念术语
-
元素尺寸:包含
padding、borde、content部分的尺寸,可以通过offsetWidth、offsetHeight获取。也被称为 “元素偏移尺寸” -
元素内部尺寸:包含
padding不包含border,也就是元素的padding box尺寸。通过clientWidth、clientHeight获取。同时也被称为 “元素可视尺寸”(不含滚动条的宽度) -
元素外部尺寸:包含
padding、border、margin、content,也就是元素的margin box尺寸。
margin 与元素的内部尺寸
当元素设置了 width 属性或者当元素具有 “包裹性” 的时候,margin 对尺寸是没有影响的。只有当元素是 “充分利用可用空间” 的时候,margin 才可以改变元素的可视尺寸。
<div style="margin-left: 100px;">
<div style="background: #ccc">123</div>
</div>
同样,垂直方向也是可以的
<div style="position: relative; width: 100px; height: 100px; background: #333">
<div style="background: #ccc; position: absolute; top: 0; bottom: 0; margin-top: 30px;">123</div>
</div>
上面的 demo 可以看出来,当前元素表现为 “格式化宽高” 的时候,元素自动充满父容器的宽度和高度,这个时候 margin\border\padding\content 自动分配水平和垂直方向空间。当元素表现为正常流特性的时候,和 “格式化宽度” 是一样的。
看看下面的几个 demo
<div style="background: #ccc; overflow: hidden">
<img src="./static/images/timg.jpg" alt="" class="right">
<div class="left">1234567890</div>
</div>
.left {
margin-right: 100px;
}
.right {
float: right;
width: 100px;
}
<div style="background: #ccc; overflow: hidden">
<img src="./static/images/timg.jpg" alt="" class="left">
<div class="right">1234567890</div>
</div>
.right {
margin-left: 100px;
}
.left {
float: left;
width: 100px;
}
<div style="background: #ccc; overflow: hidden">
<div class="middle">
<div class="con">1234567890</div>
</div>
<img src="./static/images/timg.jpg" alt="" class="left">
<img src="./static/images/timg.jpg" alt="" class="right">
</div>
.right {
float: left;
width: 100px;
margin-left: -100px;
}
.left {
float: left;
width: 100px;
margin-left: -100%;
}
.middle {
/*margin: 0 100px;*/
float: left;
width: 100%;
}
.con {
margin: 0 100px;
}
<div style="background: #ccc; overflow: hidden">
<img src="./static/images/timg.jpg" alt="" class="left">
<img src="./static/images/timg.jpg" alt="" class="right">
<div class="middle">
<div class="con">1234567890</div>
</div>
</div>
.right {
float: right;
width: 100px;
}
.left {
float: left;
width: 100px;
}
.middle {
width: 100%;
}
.con {
margin: 0 100px;
}
注意: 这个时候当 margin 为负值的时候,容器的 width 会增加
<div style="margin-right: -30px; background: #333; text-align: right">1234567890</div>
margin 与元素的外部尺寸
在 CSS 世界中很多棘手的问题都是需要借助 margin 的外部尺寸特性来实现的。比方说, FireFox 浏览器下,设置了 overflow: auto/scroll 的容器会忽略 padding-bottom 值。
<div style="padding: 50px; background: #ccc; height: 200px; overflow: scroll;">
<img src="./static/images/timg.jpg" alt="" height="300px">
</div>
注意:如果 padding-bottom 属性的数值设置的过小,则看不出是否被忽略的效果,所以这里我设置的是 50px
那么对于上面的问题,我们可以在最后一个子元素中设置 margin-bootom 来替换就可以了。
margin 和 padding 之间的相互作用
当 margin 为负值的时候,“元素尺寸” 就会变大。这个时候,如果 padding/border 是固定的数值,那么 content (这里的 width 的值为 auto)就会随着 margin 负值的增加而变大,但对于 height 来说,没有任何影响(不会影响 height 值)。
注意:不是定位方向的 margin 是不会对元素的定位产生影响的,只能对该元素后面相邻的元素定位产生影响。
我们这里有一个需求是:一个盒子内部需要让左右两栏的背景高度一致,取最高那部分的高度。(使用 margin 和 padding 互补)
<div style="max-height: 200px; overflow: hidden;">
<div style="float: left; width: 50%;background: #ccc; padding-bottom: 500px; margin-bottom: -500px;">
<p>1213r</p>
<p>1213r</p>
<p>1213r</p>
<p>1213r</p>
<p>1213r</p>
<p>1213r</p>
<p>1213r</p>
<p>1213r</p>
</div>
<div style="float: left; width: 50%; background: #444; padding-bottom: 500px; margin-bottom: -500px;">
456
</div>
</div>
padding 和 margin 互补部分的尺寸是不会计算到布局定位中的
margin 的百分比值 和 padding 一样都是相对于父容器的 width 进行计算的
margin 的合并
块级元素的上、下外边距有时候是会发生合并的,发生 “margin合并” 必须满足两点重要信息
- 块级元素,但不包含浮动、绝对定位元素
- 只发生在垂直方向上
哪些场景会发生合并:
-
相邻兄弟元素
margin合并 -
父容器和第一个字元素的
margin合并(子元素大于1个,发生margin-top合并)
<div style="height: 200px; background: #444">
<div style="width: 50%; height: 50px; background: #ccc; margin-top: 100px">
</div>
</div>
这个时候的 margin 会合并到父元素上,也就是说 margin-top 实际上是作用在父元素上
- 父容器和最后一个子元素的
margin合并(子元素大于1个,发生margin-bottom合并)
<div style="background: #444">
<div style="width: 50%; height: 50px; background: #ccc; margin-bottom: 100px">
</div>
</div>
这个时候的 margin 会合并到父元素上,也就是说 margin-bottom 实际上是作用在父元素上。注意:这个时候父元素不能设置 height 属性
- 父容器只含有一个子元素的时候,且父元素没有设置
height属性,那么margin-top、margin-bottom都可能与父元素发生 “margin合并”。如果设置了height属性,那么就不会发生margin-bottom的合并。注意,这里的合并最终效果都是作用在了父元素身上。
<div style="background: #444">
<div style="width: 50%; height: 50px; background: #ccc; margin: 100px">
</div>
</div>
如何消除 margin-top 合并
-
父元素设置 BFC 块级格式化上下文
-
父元素设置 border-top
-
父元素设置 padding-top
-
在父元素和第一个字元素之间添加一个 内联元素 进行分隔
如何消除 margin-bottom 合并
-
父元素设置 BFC 块级格式化上下文
-
父元素设置 height 、min-height 或者 max-height
-
父元素设置 border-bottom
-
父元素设置 padding-bottom
-
在父元素和最后一个字元素之间添加一个 内联元素 进行分隔
如果一个元素是一个空元素(没有任何内容),那么如果同时设置了 margin-top 和 margin-bottom。那么这个时候 margin-top 和 margin-bottom 是会发生合并的。所以实际定位时只计算一个 margin-top/margin-bottom 的值(谁的值大取谁)。如何消除这种情况的 margin 合并
- 设置垂直方向的 padding
- 设置垂直方向的 border
- 里面添加内联元素(直接 space 键空格是没用的)
- 设置 height 或者 min-height
margin 合并的计算规则:
- 如果元素的
margin都是正值,那么取最大的那个 - 如果元素的
margin一正一负,那么取正负相加后的值 - 如果元素的
margin都是负值,那么取最负的那个
margin: auto 作用机制
- 正常流
** 对于
margin-left、margin-right,如果一侧定值一侧为auto,那么auto为剩余空间大小
<div style="width: 100px; margin: 0 0 0 auto; background: #ccc">123</div>
<div style="width: 100px; margin: 0 auto 0 0; background: #444">123</div>
** 对于 margin-left、margin-right,如果都为 auto,那么 平分剩余空间
<div style="width: 100px; margin: 0 auto; background: #444">123</div>
-
格式化宽高
**
margin-left、margin-right或者margin-top、margin-bottom,如果一侧定值一侧为auto,那么auto为剩余空间大小
<div style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; width: 200px; height: 200px; margin: 100px auto 0; background: #444">123</div>
<div style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; width: 200px; height: 200px; margin: auto auto 0; background: #444">123</div>
** 对于 margin-left、margin-right 或者 margin-top、margin-bottom,如果都为 auto,那么 auto 为剩余空间大小
<div style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; width: 200px; height: 200px; margin: 0 auto; background: #444">123</div>
<div style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; width: 200px; height: 200px; margin: auto auto; background: #444">123</div>
下面的这个案例就可以完美的解释 margin: auto
<div style="width: 300px; background: #ccc">
<div style="width: 200px; margin-left: auto; margin-right: 80px; background: #455">123</div>
</div>
什么情况下设置的 margin 无效
-
display计算值为inline的非替换元素的margin-top、margin-bottom。内联替换元素的垂直margin是有效的,并且没有margin合并的问题,所以图片不会发生 “margin合并” -
表格中的
<tr>、<td>元素或者设置display: table-cell | table-row的元素的margin都是无效的 -
margin合并的时候,更改margin值可能是没有效果的(只有当更改的那个margin值大于另外一个marin值时才会生效)。 -
绝对定位元素非定位方位的
margin值 “无效”。其实并不是margin没有生效,实际上,绝对定位元素任意方位的margin值无论在什么场景下都是一直有效的,比如下面的 demo 。这种情况,margin-bottom: 80px其实增加了元素的外部尺寸。所以在元素的底部和父元素的底部间隔 80px。
<div style="width: 300px; height: 100px; background: #ccc; overflow: auto; position: relative;">
<div style="position: absolute; top: 0; left: 0; height: 100px; margin-top: 100px; margin-bottom: 80px; background: #455">123</div>
</div>
- 正常流水平方向上的
margin-right或者margin-bottom都是 “无效”。对元素的定位是不起作用的。但是这种情况和上面的 demo 一样,会增加元素的外部尺寸。
<div style="width: 300px; background: #ccc; overflow: auto;">
<div style="height: 100px; margin-top: 100px; margin-bottom: 80px; background: #455">123</div>
</div>
这种情况也可以该改变。给元素设置 float: right 后,那么这个时候 right 就成了定位方向了,这个时候 margin-right 就起作用了。
border
border-width
-
thin- 薄薄的,等于1px; -
medium- 薄厚均匀,等于3px;默认值。 -
thick- 厚厚的,等于4px
border-style 默认值就是 none。所以当我们设置 border-width 和 border-color 没有显示边框的原因。但是当我们只设置 border-style: solid 就会出现边框。
-
none- 无,默认值 -
solid- 实线边框 -
dashed- 虚线边框 -
dotted- 虚点边框 -
doubble- 双线边框:当border-width小于 3px 的时候,展示的只有一条边框线。 -
inset- 内凹槽 -
outset- 外凸槽 -
groove- 沟槽 -
ridge- 山脊