盒子模型
都是网上收集的资料,非原创。仅供自己学习做笔记用的,只是为了分享自己的笔记,侵权就删
盒子模型
结构
为了给文档树中的各个元素排版定位(布局),浏览器会根据渲染模型为每个元素生成四个嵌套的矩形框, 分别称作 content box、padding box、border box 和 margin box,它们是不可分割的,并可能会重合, 这就是 CSS 规范中描述的“框模型”(box model)。它是以 CSS 的角度去看一个元素被渲染后的抽象形态。 是一个元素自身的构成部分,不同于布局:多个元素在页面上的定位。
上面的大框,代表一个元素生成的矩形区域( box ),每一个 box 都包括一个 content 区域(元素的内容,如文本,图形等)以及环绕其四周的 padding (元素的内边距,填充部分)、border (元素的边框) 和 margin (元素的外边距) 区域。
注:
- 元素在页面上定位及布局的规则,包括 'position' 和 'float' 等等,详见: W3C CSS2.1 -- 9 Visual formatting model
边界
上述四个区域(content、 padding、border 和 margin)分别有他们自己的边界,细化来说,每个区域都有 top、right、bottom、left 四个边界。
- Content 边界/内边界:Content 边界环绕在由该元素的宽和高决定的一个矩形上,这个尺寸通常由该元素渲染后的内容决定。 这四个 content 边界组成的矩形框就是该元素的 content box。
- Padding 边界:Padding 边界环绕在该元素的 padding 区域的四周,顾名思义,填充背景色,在此范围内有效。如果 padding 的宽度为0, 则 padding 边界与 content 边界重合。这四个 padding 边界组成的矩形框就是该元素的 Padding box。
-
padding 是 'padding-top', 'padding-right', 'padding-bottom', 'padding-left' 的缩写。默认值是 0。
可以应用到的元素:除 display 值是 ‘table-row-group’,‘table-header-group’, ‘table-footer-group’, ‘table-row’, ‘table-column-group’ 和 ’table-column’ 的所有元素。
- Border 边界:Border 边界环绕在该元素的 border 区域的四周,如果 border 的宽度为0,则 border 边界与 padding 边界重合。 这四个 border 边界组成的矩形框就是该元素的 border box。
- Margin 边界/外边界:Margin 边界环绕在该元素的 margin 区域的四周,如果 margin 的宽度为0,则 margin 边界与 border 边界重合。 这四个 margin 边界组成的矩形框就是该元素的 margin box。
margin 非 table 类型的元素,以及 table 类型中 table-caption, table 和 inline-table 这3类。例如 TD TR TH 等,margin 是不适用的。 并且,对于行内非替换元素(例如 SPAN),垂直方向的 margin 不起作用。
所有元素都是一个盒子,内部是内容区(文本,或者图像类),内容区外面是内边距padding(内容区与边框的距离,可有可无),之后是边框(围绕内容的一条线,有各种不同宽度,颜色,样式),最外面是外边距margin(两个盒子之间距离)。盒子元素模型,会随着padding和border元素的加入,而增加实际占用空间
不能对内边距,外边距指定样式,颜色。它们会呈现背景颜色图案。
border-style 边框样式solid实线,groove槽线,double双线,outset外凸,dotted虚线,dashed破折线,inset内凹,ridge脊线。
.外边距,内边距设置 margin 0px(上下) 20px(右左), margin20px(上下右左),margin10px 10px 10px 10px (上右下左 ) margin10px 5px 15px (上10px右左5px下15px)
两个块元素上下放置在一起时,会折叠外边距,以两个块元素之间较大的那个外边距为共同边距,如果是在脱离标准文档流中,竖直方向的margin叠加
包含块
在 CSS2.1 中,很多框的定位和尺寸的计算,都取决于一个矩形的边界,这个矩形,被称作是包含块( containing block )。 一般来说,(元素)生成的框会扮演它子孙元素包含块的角色;我们称之为:一个(元素的)框为它的子孙节点建造了包含块。包含块是一个相对的概念。
包含块的作用是为它里面包含的元素提供一个参考,元素的尺寸和位置的计算往往是由度该元素所在的包含块决定的。 某元素的包含块,就是包含这个某元素元素的块。
以上代码为例,DIV 和 TABLE 都是包含块。DIV 是 TABLE 的包含块,同时 TABLE 又是 TD 的包含块,不是绝对的。
“一个框的包含块”,指的是“该框所存在的那个包含块”,并不是它建造的包含块。比如,上述代码中,TABLE 的包含块,说的是 DIV 建造的包含块,而不是 TABLE 自身建造的包含块。TABLE 建造的包含块,可以称作 TD 的包含块。
每个框关于它的包含块都有一个位置,但是它不会被包含块限制;它可以溢出(包含块)。包含块上可以通过设置 'overflow' 特性达到处理溢出的子孙元素的目的。
根元素
根元素,就是处于文档树最顶端的元素,它没有父节点。
根元素存在的包含块,被叫做初始包含块 (initial containing block)。具体,跟用户端有关。
- 在 (X)HTML 中,根元素是 html 元 素(尽管有的浏览器会不正确地使用 body 元素)。
- 而初始包含块的 direction 属性与根元素相同。
静态定位元素和相对定位元素
如果该元素的定位(position)为 "relative" (相对定位)或者 "static"(静态定位),它的包含块由它最近的块级、单元格(table cell)或者行内块(inline-block)祖先元素的 内容框创建。
元素如果未声明 'position' 特性,那么就会采用 'position' 的默认值 "static"。
固定定位元素
如果元素是固定定位 ("position:fixed") 元素,那么它的包含块是当前可视窗口。
绝对定位元素
总的来说,绝对定位("position: absolute")元素的包含块由离它最近的 'position' 属性为 'absolute'、'relative' 或者 'fixed' 的祖先元素创建。,如果没有,包含块为根元素
如果其祖先元素是行内元素,则包含块取决于其祖先元素的 'direction' 特性
1). 如果 'direction' 是 'ltr',包含块的顶、左边是祖先元素生成的第一个框的顶、左内边距边界(padding edges) ,右、下边是祖先元素生成的最后一个框的右、下内边距边界(padding edges)
示例代码:
以上代码中,文字采取默认从左到右的方式排列。红 XX 和 蓝 XX 和黄 XX 都是绝对定位元素,它的包含块是相对定位的 SPAN。 它们定位需要参照包含块,按照标准来说,它们包含块的左顶边是 SPAN 形成的第一个框(即第一行的灰色部分)的顶、左内边距边,包含块的右、下边是 SPAN 生成的最后一个框(最后一行灰色的部分)的右、下内边距边界。
示意图:
行内元素内形成的包含块,在各浏览器中各不相同,存在兼容性问题。可以通过上面的例子可以证明这一点。蓝色的 "XX" 的位置在各浏览器中都不一样。
包含块的宽度可能是负的。
示例代码:
示意图:
以上的边界无法围成一个区域,在这种情况下,包含块的宽度是负的。
2). 如果 'direction' 是 'rtl',包含块的顶、右边是祖先元素生成的第一个框的顶、右内边距边界 (padding edges) ,左、下边是祖先元素生成的最后一个框的左、下内边距边界 (padding edges)
示例代码:
示意图:
其他情况下,如果祖先元素不是行内元素,那么包含块的区域应该是祖先元素的内边距边界
嵌套块元素垂直外边距的合并
对于两个嵌套的块元素,如果父元素没有上内边距和边框,则父元素的上外边距会与子元素的上外边距发生合并,合并后的外边距为两者中的较大者,即使父元素上外边距为0,也会发生合并(因为父元素没有上内边距和边框,所以子元素靠近了父元素上边框,子元素的外边距相对的是外面的流,不过前提是父元素跟子元素之间没有内容,要不子元素外边距对的是父元素内容)
解决方案
1、可以为父元素定义1像素上边框和上内边距
2、可以为父元素添加overflow:hidden
盒子居中
margin:0 auto
;
注意:
1)使用margin:0 auto;
的盒子,必须有width
,有明确的width
2) 只有标准流的盒子,才能使用margin:0 auto;
居中。 也就是说,当一个盒子浮动了、绝对定位了、固定定位了,都不能使用margin:0 auto
;
3) margin:0 auto;
是在居中盒子,不是居中文本。文本的居中,要使用text-align:center;
图片在盒子水平垂直居中
第一种办法(推荐)。css代码。div的display设置成table-cell,text-align为center,垂直居中设置vertical-align为middle。(vertical-align 属性设置元素的垂直对齐方式)
第二种办法。div设置成相对定位,img设置成绝对定位,然后left:50%,top:50%,此时图片的左上角将位于div的中心。重点:图片向上移动图片高度的一半,并向左移动图片宽度的一半。正好为与div正中间。
有些小图标 可以当做背景 放在padding 的空间里面
比如
padding-right:10px;
background: url(images/图标.png) no-repeat right center;
设置右padding 10px,然后把图标设置成背景 不重复 然后右居中,就可以把图标放到文字右边
盒子内容宽度
在盒子模型中,我们设置的宽度都是内容宽度,不是整个盒子的宽度
为盒子模型设置宽度,结果只是设置了内容的宽度,这个不合理。如何解决这一问题?答案就是:box-sizing:border-box(固定的盒子大小 padding增加不改变大小至改变内部位置 border改变也不会改变他的大小
content-box |
这是由 CSS2.1 规定的宽度高度行为。 宽度和高度分别应用到元素的内容框。 在宽度和高度之外绘制元素的内边距和边框。 |
border-box |
为元素设定的宽度和高度决定了元素的边框盒。 就是说,为元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。 通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度。 |
)
如上图,div设置了box-sizing:border-box之后,300px的宽度是内容 + border + 边框的宽度(不包括margin),这样就比较符合我们的实际要求了。
建议大家在为系统写css时候,第一个样式是:
border
border属性能够被拆开,有两大种拆开的方式:
1) 按3要素:border-width、border-style、border-color
2) 按方向:border-top、border-right、border-bottom、border-left
按照三要素拆开
border-width:10px 边框宽度
border-style:solid 线型
border-color:red 颜色
按方向来拆
|
等价于
|
按方向还能再拆一层,就是把每个方向的,每个要素拆开,一共12条语句:
|
边框指定圆角border-radius:15px;也可以分别指定border-top-left-radius:15px;border-top-right-radius:15px;border-bottom-right-radius;border-bottom-left-radius;
margin
善于使用父亲的padding,而不是儿子的margin
如果父亲没有border,那么儿子的margin实际上踹的是“流”,踹的是这“行”。所以,父亲整体也掉下来了
这个p有一个margin-top踹父亲,试图将自己下移
|
结果:
|
|
margin这个属性,本质上描述的是兄弟和兄弟之间的距离; 最好不要用这个marign表达父子之间的距离。
所以,我们一定要善于使用父亲的padding,而不是儿子的margin。
当元素不存在width属性或者width:auto的时候,负值margin会增加元素的宽度.(注意:这仅仅是在元素不存在width属性或则width属性默认的时候,如果有宽度设置,margin-left和margin-right为负值时,会发生位移.)
margin-bottom为负值的时候不会位移,而是会减少自身供css读取的高度.
什么是减少自身供css读取的高度呢?
不加margin-bottom:-100px的效果
可以看出,类名为box的元素的高度依旧是200px,浏览器依旧将整个元素渲染出来了,如果用console.log($(".box").height());打印box的高度,其高度依旧是200px,但是,其在浏览器中实际读取的高度减少到了100px, 类名为t的元素的位置为证.(div元素跑到了上面)
https://www.cnblogs.com/fbzs/p/6373315.html
如果margin设置成了负值,大多数情况下后面的元素会覆盖前面的元素,但是,也不总是,具体覆盖情况要分为背景和内容,以及display的属性。
在普通流布局中,浏览器将页面布局分为内容和背景,内容的层叠显示始终高于背景。block元素分为内容和背景,而inline元素或inline-block元素,它本身就是内容(包括其背景等样式设置)
总结一下就是,
虽然margin可以应用到所有元素,但display属性不同时,表现也不同,比如inline的上下margin就会无效。block的四个方向的margin都会有效,这个很好理解。
在两个block元素重叠后,后面元素可以覆盖前面元素的背景,但无法覆盖其内容
当两个inline元素,或两个line-block元素,或inline与inline-block元素重叠时,后面元素可以覆盖前面元素的背景和内容。
对文档流的影响
元素如果用了margin-left:-20px;毋庸置疑的自身会向左偏移20px和定位(position:relative)有点不一样的是,在其后面的元素会补位,也就是后面的行内元素会紧贴在此元素的之后。总结,不脱离文档流不使用float的话,负margin元素是不会破坏页面的文档流。
对浮动元素的影响
先定义3个box
<div class="container">
<div class="flb flbox1">box1</div>
<div class="flb flbox2">box2</div>
<div class="flb flbox3">box3</div>
</div>
.flb{
float: left;
width: 100px;
height: 100px;
}
.flbox1{background-color: rgba(33, 114, 214, 0.8);}
.flbox2{background-color: rgba(255, 82, 0, 0.8);}
.flbox3{background-color: rgba(90, 243, 151, 0.8);}

demo1,给他们都加上margin-left:-25px;
.flb{
float: left;
width: 100px;
height: 100px;
margin-left: -25px;
}
.flbox1{background-color: rgba(33, 114, 214, 0.8);}
.flbox2{background-color: rgba(255, 82, 0, 0.8);}
.flbox3{background-color: rgba(90, 243, 151, 0.8);}

可以看出3个盒子都向左移动25px;
box1自身向左移动了25px,box2又覆盖了其25px,所以我们就看到了“宽度”为50px的box1
box2,box3以此类推!
让我再看看margin-left: -50px;的情况

如果只给box3设置margin-left:-200px;
.flb{
float: left;
width: 100px;
height: 100px;
}
.flbox1{background-color: rgba(33, 114, 214, 0.8);}
.flbox2{background-color: rgba(255, 82, 0, 0.8);}
.flbox3{background-color: rgba(90, 243, 151, 0.8);
margin-left: -200px;}

看一看到box3,向左偏移了200px,完全将box1覆盖了,box3下面还能隐约的看到了box1。
总结:
负margin会改变浮动元素的显示位置,即使我的元素写在DOM的后面,我也能让它显示在最前面。圣杯布局、双飞翼布局啊什么的,都是利用这个原理实现的。(下文有详细)
对绝对定位影响
<div class="absolute"></div>
.absolute{
position: absolute;
top:50%;
left:50%;
height: 200px;
width: 200px;
background-color: #ccc;
margin-top: -100px;
margin-left: -100px;
}

对于绝对定位元素,负margin会基于其绝对定位坐标再偏移,
唯有的缺点就是你必须知道这个觉得定位元素宽度的和高度才能并设置负margin值使其居中浏览器窗口,
若对于不确定宽度和高度可以用
transform: translate3d(-50%,-50%,0);
使用translate3d可以开启GPU加速,就不用cpu去从新计算所有点素位置,开启GPU加速后,GPU自动将这个元素放在一个新的“层”,直接偏移这个“层”来提高渲染速度
二、margin为负值的常见布局应用
左右固定,中间自适应(双飞翼)
双飞翼的好处:
1.可以让主要内容出现在dom结构的前面,现将主要内容渲染
2.中间自适应,两边固定宽度的效果

<div class="main">
<div class="main-content">main content</div>
</div>
<div class="left">left</div>
<div class="right">right</div>
*{
margin:0;
padding: 0
}
.main{
float: left;
width: 100%;
}
.main .main-content{
margin: 0 210px;
background-color: rgba(33, 114, 214, 0.8);
height: 500px
}
.left{
width: 200px;
float: left;
background-color: rgba(255, 82, 0, 0.8);
margin-left: -100%;//当margin-left为百分比的,那么这个百分比是以父元素的内容长度的百分比,
也就是去除父元素的padding magin bord长度留下来的内容长度的百分比,
.left向左移动body width的100%。但是因为在第二排移动到第一排的时候,已经移动了自身距离200px,所以会出现在第一排靠左边
可以用calc(-100% + 5px)验证得得出 left在第一排就是移动了整个body距离 -200px。
calc()可以让百分比比px混用,记得+号前后加空格
height: 200px
}
.right{
width: 200px;
height: 200px;
margin-left: -200px;
float: left;
background-color: rgba(90, 243, 151, 0.8);
}
去除列表右边框
利用负margin增加宽度的特点,举个在实际中应用例子🌰
对于图片列表,我会常常设计成两边对齐,中间元素平均分布,类似下面的布局

想让每一排最后一个对齐父元素的右边框,一般都两种处理,第一种会在给个循环体内的最后一个添加一个float:right属性或者做特殊处理,但这样还需要后端配合,我们自己能解决的就尽量自己解决。还有就是用css3的flexbox布局能解决这个两边对齐,但是这种布局兼容性不好,你的用户用IE的话,不推荐!
so,负margin就能发挥其增加元素宽度的特点,完美的解决这个问题!
<div class="container"> <ul class="list"> <li>我是一个列表</li> <li>我是一个列表</li> <li>我是一个列表</li> <li>我是一个列表</li> <li>我是一个列表</li> <li>我是一个列表</li> <li>我是一个列表</li> <li>我是一个列表</li> <li>我是一个列表</li> <li>我是一个列表</li> </ul> </div>
*{
margin:0;
padding:0;
}
.container{
margin:0 auto;
width: 500px;
border: 1px #ccc solid;
margin-bottom: 20px;
}
.list{
overflow: hidden;
margin-right: -10px;
}
.list li{
width:92px;
height: 92px;
background-color: #ccc; margin-bottom: 20px;
float: left;
margin-right: 10px;
}

计算公式:
假设一横列展示的数量为x,元素间的间距为y,父宽度z
则元素的宽度=(z-y(x-1))/x
本例中li的宽度为(500-10(5-1))/5=92
负边距+定位:水平垂直居中
上面已经举例,用了负margin会向对应方向偏移的特点!
去除列表最后一个li元素的border-bottom
很多情况下,我们会用li标签来模拟表格,再给li标签添加下边距的时候,最后一个li标签表格会和父元素的边框靠在一起,会显得整个“table”的底部边框会比其他的边粗一些!
<style>
ul.table{
border:1px #ccc solid;
margin-top:100px;
}
ul.table li{
border-bottom: 1px #ccc solid;
list-style: none;
}
</style>
<ul class="table">
<li>I am li</li>
<li>I am li</li>
<li>I am li</li>
<li>I am li</li>
<li>I am li</li>
</ul>

下面添加一个margin-bottom:-1px;的属性,就可以使其看起来更完美
<style>
ul.table{
border:1px #ccc solid;
margin-top:100px;
}
ul.table li{
border-bottom: 1px #ccc solid;
list-style: none;
margin-bottom: -1px;
}
</style>
<ul class="table">
<li>I am li</li>
<li>I am li</li>
<li>I am li</li>
<li>I am li</li>
<li>I am li</li>
</ul>

多列等高
利用margin-bottom为负值会减少css读取元素高度的特性,加上padding-bottom和overflow:hidden,就能做一个未知高度的多列等高布局(当然也可以用table)
<style>
.container{
margin:0 auto;
width: 100%;
overflow: hidden;
}
.left{
height: 50px;
width: 33.33%;
margin-bottom: -5000px;
padding-bottom: 5000px;
float: left;
background-color: rgba(33, 114, 214, 0.8);
}
.main{
height:100px;
margin-bottom: -5000px;
width: 33.33%;
float: left;
padding-bottom: 5000px;
background-color: rgba(255, 82, 0, 0.8);
}
.right{
width: 33.33%;
float: left;
margin-bottom: -5000px;
padding-bottom: 5000px;
background-color: rgba(90, 243, 151, 0.8)
}
</style>
<div class="container">
<div class="left"> height:50px</div>
<div class="main">height:100px</div>
<div class="right">height:30px</div>
</div>

虽然设置了5000的内边距,但是我用-5000的外边距去抵消掉,所以对于父元素来说(上文所说的css能读取的高度),他还是原来的高度(但其自身实际高度为5000p x+本来高度),然后父元素在加上overflow:hidden;以最高的高度进行裁切,所以就有了看起来“等高”的3个div。
作者:琦乐无穷
链接:https://www.jianshu.com/p/549aaa5fabaa
关于margin的IE6兼容问题
IE6双倍margin bug
当出现连续浮动的元素,携带和浮动方向相同的margin时,队首的元素,会双倍marign。
|
解决方案:
1)使浮动的方向和margin的方向,相反。
所以,你就会发现,我们特别喜欢,浮动的方向和margin的方向相反。并且,前端开发工程师,把这个当做习惯了。
|
2)使用hack(没必要,别惯着这个IE6)
单独给队首的元素,写一个一半的margin
|
|
IE6的3px bug
解决办法:
不用管,因为根本就不允许用儿子踹父亲。所以,如果你出现了3px bug,说明你的代码不标准