css盒子模型

2021年 11月 28日 57点热度 0人点赞

引言

盒子模型, 英文即 box model. 无论是 div, span, 还是 a 都是盒子.

但是, 图片, 表单元素一律看作是文本, 它们并不是盒子. 这个很好理解, 比如说, 一张图片里并不能放东西, 它自己就是自己的内容.

file

所有 HTML 元素可以看作盒子, 在 CSS 中,"box model"这一术语是用来设计和布局时使用.

CSS 盒模型本质上是一个盒子, 封装周围的 HTML 元素, 它包括: 边距, 边框, 填充, 和实际内容.

盒模型允许我们在其它元素和周围元素边框之间的空间放置元素.

下面的图片说明了盒子模型 (Box Model):

file

不同部分的说明:

  • Margin(外边距) - 清除边框外的区域, 外边距是透明的.
  • Border(边框) - 围绕在内边距和内容外的边框.
  • Padding(内边距) - 清除内容周围的区域, 内边距是透明的.
  • Content(内容) - 盒子的内容, 显示文本和图像.

CSS 盒模型和 IE 盒模型的区别

  • 在 标准盒子模型中, width 和 height 指的是内容区域的宽度和高度. 增加内边距, 边框和外边距不会影响内容区域的尺寸, 但是会增加元素框的总尺寸.
  • IE 盒子模型中, width 和 height 指的是 内容区域 + border + padding 的宽度和高度.

注:Android 中也有 margin 和 padding 的概念, 意思是差不多的, 如果你会一点 Android, 应该比较好理解吧. 区别在于, Android 中没有 border 这个东西, 而且在 Android 中, margin 并不是控件的一部分, 我觉得这样做更合理一些, 呵呵.

有必要强调一下, <body> 也有 margin. 很多人以为 <body> 标签占据的是整个页面的全部区域, 其实是错误的, 正确的理解是这样的: 整个网页最大的盒子是<document>, 即浏览器. 而 <body><document>的儿子. 浏览器给 <body> 默认的 margin 大小是 8 个像素, 此时 <body> 占据了整个页面的一大部分区域, 而不是全部区域.

元素的宽度和高度

当您指定一个 CSS 元素的宽度和高度属性时, 你只是设置内容区域的宽度和高度. 要知道, 完整大小的元素, 你还必须添加内边距, 边框和外边距.

下面的例子中的元素的总宽度为 300px:

div {
    width: 300px;
    border: 25px solid green;
    padding: 25px;
    margin: 25px;
}

让我们自己算算:

300px (宽)+ 50px (左 + 右填充)+ 50px (左 + 右边框)+ 50px (左 + 右边距)= 450px

试想一下, 你只有 250 像素的空间. 让我们设置总宽度为 250 像素的元素:

div {
    width: 220px;
    padding: 10px;
    border: 5px solid gray;
    margin: 0;
}

最终元素的总宽度计算公式是这样的:

总元素的宽度=宽度+左填充+右填充+左边框+右边框+左边距+右边距

元素的总高度最终计算公式是这样的:

总元素的高度=高度+顶部填充+底部填充+上边框+下边框+上边距+下边距

宽度和真实占有宽度, 不是一个概念!

如果想保持一个盒子的真实占有宽度不变, 那么加 width 的时候就要减 padding. 加 padding 的时候就要减 width. 因为盒子变胖了是灾难性的, 这会把别的盒子挤下去.

padding 区域也有颜色

padding 就是内边距.padding 的区域有背景颜色, css2.1 前提下, 并且背景颜色一定和内容区域的相同. 也就是说,background-color 将填充所有 border 以内的区域.

要懂得, 用小属性层叠大属性.

下面的写法:

padding-left: 30px;
padding: 20px;

第一行的小属性无效, 因为被第二行的大属性层叠掉了.

一些元素, 默认带有 padding, 比如 ul 标签. 不加任何样式的 ul, 也是有 40pxpadding-left. 所以, 我们做站的时候, 为了便于控制, 总是喜欢清除这个默认的 padding.

可以使用*进行清除:

* {
    margin: 0;
    padding: 0;
}

但是,* 的效率不高, 所以我们使用并集选择器, 罗列所有的标签 (不用背, 有专业的清除默认样式的样式表, 今后学习):

body, div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,
fieldset, legend,input,textarea,p,blockquote,th,td {
    margin:0;
    padding:0;
}

border 就是边框. 边框有三个要素: 像素 (粗细), 线型, 颜色.

颜色如果不写, 默认是黑色. 另外两个属性不写, 要命了, 显示不出来边框.

如果公司里面的设计师是处女座的, 追求极高的页面还原度, 那么不能使用 css 来制作边框. 就要用到图片, 就要切图了.

所以, 比较稳定的 border-style 就几个:solid, dashed,dotted.

利用 border 画一个三角形

举例: 利用 border 属性画一个三角形 (小技巧)

  • 设置盒子的 width 和 height 为 0;
  • 然后将 border 的底部取消;
  • 最后设置 border 的左边和右边为白色;
div {
  width: 0px;
  height: 0px;
  border: 50px solid white;
  border-top-color: red;
  border-bottom: none;
}

margin 塌陷

同级塌陷

两个同级元素, 垂直排列. 上面的盒子给了 margin-bottom, 下面的盒子给了 margin-top. 那么这两个边距将会重叠, 按照大的值来计算.

解决办法: 简单粗暴地不让这两个边距同时出现.

嵌套塌陷

在两个盒子嵌套时候, 内部的盒子设置的 margin-top 会加到外边的盒子上, 导致内部的盒子 margin-top 设置失败, 解决方法如下:

  • 外部盒子设置一个边框, 给父盒子设置 border, 添加 border 后父盒子和子盒子就不会贴在一起了, 这里可以给边框颜色设置为透明色 这样不会影响效果
  • 外部盒子设置 overflow:hidden, 使用 overflow 元素溢出属性, hidden 内容被修剪, 修剪内容不显示。不建议应用时使用, 因为有的格式需要设置溢出, 不能 hidden。
  • 使用伪元素类: .clearfix:before { content: ''; display: table;}, 类似于第一种给外部盒子加边框方式, 是使用较多的

外边距合并

外边距合并指的是, 当两个垂直外边距相遇时, 它们将形成一个外边距. 合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者. 解决方法如下:

  1. 使用这种特性
  2. 设置一边的外边距, 一般设置 margin-top
  3. 将元素浮动或者定位

margin 相关技巧

  • 设置元素水平居中: margin: x auto;
  • margin 负值让元素位移及边框合并

注: 背景颜色填充到 margin 以内的区域包括 border. padding 不能为负, margin 可以为负.

box-sizing: 盒尺寸

默认值: content-box, 指 width, height 只为 content 的宽高.

给子元素添加 padding 值, 当未添加 box-sizing 属性时, 默认为 content-box, 盒子就会变大. 此时若规定 box-sizing: border-box, 盒子大小不变, content 区域将自适应变小.

使用场景:

  • 不用再去计算一些值.
  • 解决了一些 100%问题.

盒子模型的一些问题:

margin 叠加

上下两个块都存在 margin 时, 会取上下两个中较大的一个 margin 值作为叠加的值, 左右不会存在问题.

#box1{width: 400px;height: 400px;border: 1px black solid;margin: 40px auto;}
#box2{width: 150px;height: 150px;background: red; padding:20px; margin: 20px}
#box3{width: 150px;height: 150px;background: blue;margin: 30px;}

box2 和 box3 之间 margin 值应该是 50px, 但因为上下 margin 值叠加, 取两个的最大值为叠加值, 所以为 box3 的 30px.

解决办法:

  1. 只给一个添加 margin 值.
  2. BFC 规范.

margin 传递问题

出现在嵌套结构中, 只针对 margin-top 的问题.

#box1{width: 400px;height: 400px;background: blue;}
#box2{width: 150px;height: 150px;background: red; margin-top: 120px;}

并没有给外层父容器 box1 添加 margin-top 值, 但 box1 也向下移动了.

解决办法:

  1. 给父容器添加边框.
  2. 将 margin 换成 padding.
  3. BFC 规范.

扩展

  1. margin 左右自适应是可以的, 但上下自适应不行. 代码 margin: 0 auto.
  2. width, height 不设置的话, 对盒子模型的影响: 自适应父容器, 会自动计算容器大小, 节省代码.

我们平常给元素加上的 width, height 实际上就是给内容区域加宽和高. 我们增加内外边距的时候不改变内容区域的大小, 却会改变整体的大小. 如果我们为元素加一个 1 像素的框的话, 那么我们能看见的只是框里面的东西 (内边距+内容区域), 如果在元素上添加背景, 背景也会应用于这一区域, 而外边距是不可见的, 它是用来分隔各个元素.

虽然外边距是不可见的, 但是我们算元素的总宽度或者总高度的时候, 要加上外边距.

外边距的合并问题
什么是合并
就是外边距中会有叠加的情况, 取两者中最大的一个作为间隔

合并问题的前提是
处于普通流两个或多个块元素垂直方向上相遇加粗文字, 会造成的 margin 折叠

除去普通流, 两个或多个, 块元素, 垂直很好理解之外

这个相遇要好好解释一下了, 什么算相遇呢?

简单的来说, 无非就是就是说两个元素碰到了一起. 这个相遇就是真真正正的遇到了, 如果有边框等阻挡, 是不会发生折叠的!

具体的, 分为:

父元素的上外边距和第一个子元素的上外边距, 也就是父元素的 margin-top 和 第一个子元素的 margin-top 相遇,

可以看出来红色方块原本应该在蓝色方块的下方 20px 处, 然而却合并了!

这种合并有时候是一种便利, 而在有些情况却成为了不知何处的 bug. 所以在后面会讲怎么消除这种浮动.

Ⅱ: 父元素的下外边距和最后一个子元素的下外边距
也就是父元素的 margin-bottom 与最后一个子元素的 margin-bottom 相遇发生的重叠.

与上一个类似, 所以不再阐述.

Ⅲ: 相邻兄弟姐妹元素
相邻兄弟就是, 相邻的两个元素 margin-top 和 margin-bottom 发生的合并.

Ⅳ: 空元素 , 自己的上外边距会和自己的下外边距合
clipboard.png

<p style="margin-bottom: 0px;"> 这个段落的和下面段落的距离将为 20px</p>

<div style="margin-top: 20px; margin-bottom: 20px;"></div>

<p style="margin-top: 0px;"> 这个段落的和上面段落的距离将为 20px</p>

这样第一个 p 元素和第三个 p 元素之间距离为 20px

阻止自动合并
从定义出发会很好的理解这个问题, 我们可以从合并的前提的角度出发探讨几种阻止合并的方法:

第一种方法: 摆脱普通流
position:absolute;
float:left/right;

第二中方法: 变成非块元素
第一篇文章已经提过可以用 display:inline; 将块元素变成行内元素.

注意: 用这种虽然是理论上是可以实现的, 然而它行内元素除了图片是不能设置宽高的, 同时 margin-top margin-bottom 也将失效, 所以我认为实际实现不了.

其实除了行内元素和块级元素, 还有一种元素 inline-block, 它集合两者的优点.(之后会有专门一篇文章总结.)

所以用 display:inline-block 也可以实现.

避免相遇
最重要的前提就是两个元素相遇, 才有可能合并, 我们只需要把它们隔断!

那么在相遇的两个 margin 中间可以有什么呢?
我针对两种情况给出了图解.
图片描述

由此可以很清楚的看出来, 只有父子的情况才能用这种方法.

而且方法也很显而易见: 在父级元素设置 padding 或者 border!

对于父子元素来说, 还有一种方式:
清除浮动, overflow:hidden overflow:auto 即可, 关于为什么能清除浮动还没有搞清楚.

针对父子元素的方法
设置了清除浮动属性

注意

如果有负外边距, 合并后外边距为最大正边距加上最小负边距 (绝对值最大的一个), 如上面元素下边距为 20px, 下面元素上边距为-20px, 则最后为 0px.
在实际的情况, 可以只写 margin-bottom 或者 margin-top 避免出现这种情况.

非块元素如何显示?

为此我专门写了一篇文章: 细究内联元素 (你一定不知道的东西)(同样的以后再上链接.)

CSS 盒模型详解

可以认为每个 html 标签都是一个方块, 然后这个方块又包着几个小方块, 如同盒子一层层的包裹着, 这就是所谓的盒模型.
盒模型分为 IE 盒模型和 W3C 标准盒模型.

IE 盒模型和 W3C 标准盒模型的区别是什么?

W3C 标准盒模型

属性 width, height 只包含内容 content, 不包含 border 和 padding.

IE 盒模型

属性 width, height 包含 border 和 padding, 指的是 content+padding+border.
在 ie8+浏览器中使用哪个盒模型可以由 box-sizing(CSS 新增的属性) 控制, 默认值为 content-box, 即标准盒模型; 如果将 box-sizing 设为 border-box 则用的是 IE 盒模型. 如果在 ie6, 7,8 中 DOCTYPE 缺失会触发 IE 模式. 在当前 W3C 标准中盒模型是可以通过 box-sizing 自由的进行切换的.

content-box(标准盒模型)

width = 内容的宽度
height = 内容的高度

border-box(IE 盒模型)

width = border + padding + 内容的宽度
height = border + padding + 内容的高度

谷歌浏览器, 按下 F12, 然后把右边栏的滚动条拉到最下面你就会看到一个东西:

通过代码来对其进行理解, 更直观, 如下

.box{
width:200px;
height:200px;
background-color:pink;
}

此时, 盒子大小就是 content 的大小.

.box{
width:200px;
height:200px;
background-color:pink;
padding:20px;
}

此时, 盒子的长宽变成了 240x240, 显然, padding 是能够改变盒子的大小的, 这时盒子大小就等于 content+padding.

.box{
width:200px;
height:200px;
background-color:pink;
padding:20px;
border:10px solid black;
}

此时, 盒子的长宽变成了 260x260, 所以这时盒子大小就等于 content+padding+border.

.box{
width:200px;
height:200px;
background-color:pink;
padding:20px;
border:10px solid black;
margin-bottom:10px;
}
.box1{
width: 100px;
height: 100px;
background: green;
}

此时, 盒子的长宽仍为 260x260, 即盒子的大小并未发生变化.

可以看到, 盒子的底部产生了 10px 的空白.

所以说, 盒子的大小为 content+padding+border 即内容的 (width)+内边距的再加上边框, 而不加上 margin. 很多时候, 我们会错误地把 margin 算入, 若那样的话, 上面这种情形盒子的大小应该是 260x270, 但实际情况并不是这样的.

css 的盒模型由 content(内容), padding(内边距), border(边框), margin(外边距) 组成. 但盒子的大小由 content+padding+border 这几部分决定, 把 margin 算进去的那是盒子占据的位置, 而不是盒子的大小!

我们可以试着给上面的粉色方块设置 box-sizing 属性为 border-box 发现, 会发现: 无论我们怎么改 border 和 padding 盒子大小始终是定义的 width 和 height. 如下

.box{
width:200px;
height:200px;
background-color:pink;
box-sizing:border-box;
padding:20px;
}

我们在编写页面代码时应尽量使用标准的 W3C 模型 (需在页面中声明 DOCTYPE 类型), 这样可以避免多个浏览器对同一页面的不兼容.
因为若不声明 DOCTYPE 类型, IE 浏览器会将盒子模型解释为 IE 盒子模型, FireFox 等会将其解释为 W3C 盒子模型; 若在页面中声明了 DOCTYPE 类型, 所有的浏览器都会把盒模型解释为 W3C 盒模型.

参考

rainbow

这个人很懒,什么都没留下

文章评论