一、css盒子与布局相关
- 盒子内部的布局
- 盒子之间的布局visual formatting
- 脱离正常流normal flow的盒子的布局
- absolute布局上下文下的布局
- float布局上下文下的布局
- flow下的盒子的布局
- BFC布局上下文下的布局
- IFC布局上下文下的布局
- FFC布局上下文下的布局
- table布局上下文下的布局
- css grid布局上下文下的布局
- 脱离正常流normal flow的盒子的布局
1、css盒模型
页面上显示的每个元素(包括内联元素)都可以看作一个盒子,即盒模型( box model )
盒模型有4部分组成: 从内到外分别是: content padding border margin
2、标准盒模型与IE怪异盒模型
W3C 标准盒模型一个元素的宽度(高度以此类推)应该这样计算:
一个元素的宽度 = content
盒子总宽度 = margin-left + border-left + padding-left
+ width + padding-right + border-right + margin-right
IE 怪异盒模型一个元素的宽度(高度以此类推)却是这样计算的:
一个元素的宽度width = content + padding + border
盒子总宽度 = margin-left + width + margin-right
3、css如果设置那两种模型
// W3C 标准盒模型(浏览器默认)
box-sizing: content-box;
// IE 怪异盒模型
box-sizing: border-box;
4、JS 如何获取盒模型对应的宽和高
<style>
* {
margin: 0;
padding: 0;
}
#box {
100px;
height: 100px;
padding: 50px;
border: 5px solid red;
margin: 50px;
}
</style>
<div id="box" style=""></div>
<script>
let box = document.getElementById('box')
// 只能取到内联样式的宽高
console.log('style:' + box.style.width) // 100px
// 内联样式和外联样式的宽高都能取到,但只有 IE 支持
console.log('currentStyle:' + box.currentStyle.width) // 100px
// 内联样式和外联样式的宽高都能取到,几乎所有主流浏览器都支持
console.log('getComputedStyle:' + getComputedStyle(box).width) // 100px
// 内联样式和外联样式的宽高都能取到,几乎所有主流浏览器都支持,
取到的是盒子总宽度
getComputedStyle是一个可以获取当前元素所有最终使用的CSS属性值。
返回的是一个CSS样式声明对象([object CSSStyleDeclaration])
getComputedStyle与style的区别
1、只读与可写
正如上面提到的getComputedStyle方法是只读的,只能获取样式,不能设置;
.style能读能写,能屈能伸。
2、获取的对象范围
getComputedStyle方法获取的是最终应用在元素上的所有CSS属性对象
(即使没有CSS代码,也会把默认的祖宗八代都显示出来);
而element.style只能获取元素style属性中的CSS样式。
因此对于一个光秃秃的元素<p>,getComputedStyle方法返回对象中length属性值
(如果有)就是190+(据我测试FF:192, IE9:195, Chrome:253, 不同环境结果可能有差异),
而element.style就是0
console.log('getBoundingClientRect:' +
box.getBoundingClientRect().width) // 210
object.getBoundingClientRect();
会得到元素的top、right、bottom、left、width、height属性,
这些属性以一个对象的方式返回
</script>
5、叠加外边距
一个盒子都是一个整体
p {
height: 50px;
border: 1px solid #000;
backgroundcolor: #fff;
margin-top: 50px;
margin-bottom: 30px;
}
这个样式应用到3个前后相接的段落上,由于上边距和下边距相邻,你可能会认为他们之间的外边距是80(50+30)像素,但是实际上是50像素,这就是边距叠加
外边距重叠计算方式
- 全部都为正值,取最大者
- 不全是正值,则都取绝对值,然后用正值的最小值减去绝对值的最大值
- 没有正值,则都取绝对值,然后用0减去最大值
解决办法
- 底部元素设置为浮动 float:left 脱离文本流
- 底部元素的position的值为absolute/fixed 脱离文本流
- 在设置margin-top/bottom值时统一设置上或下 统一设置一个方向
6、 子元素和父元素margin值问题
父元素无 border、padding、inline content 、 clearance时,子元素的margin-top/bottom会与父元素的margin产生重叠问题
解决办法
- 外层元素添加padding 添加padding
- 外层元素 overflow:hidden 外部触发bfc
- 外层元素透明边框 border:1px solid transparent 加边框
- 内层元素绝对定位 postion:absolute 内部元素脱离文本流
- 内层元素 加float:left;或display:inline-block 内部元素脱离文本流
二、BFC
BFC
Block fomatting context = block-level box + Formatting Context
Box: Box即盒子模型;
block-level box即块级元素
display属性为block, list-item, table的元素,会生成block-level box;并且参与 block fomatting context;
inline-level box即行内元素
display 属性为 inline, inline-block, inline-table的元素,会生成inline-level box。并且参与 inline formatting context;
Formatting context
Formatting context是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系、相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context(简称IFC)。
CSS2.1 中只有BFC和IFC, CSS3中还增加了G(grid)FC和F(flex)FC
BFC 定义
BFC(Block formatting context)直译为"块级格式化上下文"。
它是一个独立的渲染区域,只有Block-level box参与,
它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。
BFC的生成
上文提到BFC是一块渲染区域,那这块渲染区域到底在哪,它又是有多大,这些由生成BFC的元素决定,CSS2.1中规定满足下列CSS声明之一的元素便会生成BFC。
- 根元素
- float的值不为none。
- overflow的值为auto,scroll或hidden。
- display的值为table-cell, table-caption, inline-block中的任何一个。
- position的值不为relative和static
BFC 原理
- Box垂直方向的距离由margin决定。属于同一个BFC(上例中是body根元素的BFC)的两个相邻Box的margin会发生重叠
- BFC 区域不会与 浮动区域重叠
- BFC 在页面上是一个独立的容器,与其他元素互不影响
- 计算 BFC 高度时,浮动元素也会参与计算
想想我们学习css时的几条规则
- Block元素会扩展到与父元素同宽,所以block元素会垂直排列
- 垂直方向上的两个相邻DIV的margin会重叠,而水平方向不会(此规则并不完全正确)
- 浮动元素会尽量接近往左上方(或右上方)
- 为父元素设置overflow:hidden或浮动父元素,则会包含浮动元素
BFC在布局中的应用
防止margin重叠(塌陷):
两个相邻Box垂直方向margin重叠
<style>
p {
color: #f55;
background: #fcc;
200px;
line-height: 100px;
text-align:center;
margin: 100px;
}
</style>
<body>
<p>Haha</p>
<p>Hehe</p>
</body>
根据BFC布局规则第二条:
Box垂直方向的距离由margin决定。属于同一个BFC(上例中是body根元素的BFC)的两个相邻Box的margin会发生重叠
我们可以在p外面包裹一层容器,并触发该容器生成一个新BFC。那么两个P便不属于同一个BFC,就不会发生margin重叠了
代码:
<style>
.wrap {
overflow: hidden;// 新的BFC
}
p {
color: #f55;
background: #fcc;
200px;
line-height: 100px;
text-align:center;
margin: 100px;
}
</style>
<body>
<p>Haha</p>
<div class="wrap">
<p>Hehe</p>
</div>
</body>
清除内部浮动:
<style>
.par {
border: 5px solid #fcc;
300px;
}
.child {
border: 5px solid #f66;
100px;
height: 100px;
float: left;
}
</style>
<body>
<div class="par">
<div class="child"></div>
<div class="child"></div>
</div>
</body>
父级高度消失
根据BFC布局规则第六条:
计算BFC的高度时,浮动元素也参与计算
为达到清除内部浮动,我们可以触发par生成BFC,那么par在计算高度时,par内部的浮动元素child也会参与计算。
.par {
overflow: hidden;
}
自适应多栏布局的:
在float中左边的高度小于中间的高度,中间的内容到左边的下面
根据BFC布局规则第四条:BFC的区域不会与float box重叠。
.main {
overflow: hidden;
}
清理浮动
清理浮动一般有两种思路:
- 利用 clear属性,清除浮动
父容器的最后添加一个空的div,设置属性clear:left
- 使父容器形成BFC
还有通用解决方案:
.clearfix:after {
content: "";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
三、IFC布局
框会从包含块的顶部开始,一个接一个地水平摆放。
摆放这些框时,它们在水平方向的 内外边距+边框 所占用的空间都会被考虑; 在垂直方向上,这些框可能会以不同形式来对齐: 水平的margin、padding、border有效,垂直无效。不能指定宽高;
行框的宽度是 由包含块和存在的浮动来决定; 行框的高度 由行高来决定
四、css设计模式
OOCSS
OOCSS(面向对象的CSS)是在2009年首次提出的,它是围绕两个原则建立的规范。第一个原则是结构和样式分离,这意味着定义结构(布局)的CSS不应该和定义样式(颜色、字体等)的CSS混杂在一起,这样我们就可以很简单的为一个应用定义新的皮肤了;第二个原则是容器和内容分离,把元素看成是一个可重用的对象,关键核心点是一个对象不管用在页面的任何位置都应该看起来是相同的。
OOCSS提供了成熟的指导规范,但是对于具体的执行规范并没有明确指出。后来出现的SMACSS采用了它的核心概念,并且添加了更多的细节,使用起来更简单了。
SMACSS
SMACSS(可扩展模块化架构的CSS)是在2011年出现的一种设计模式,它将CSS分为5个不同的类别——基本规范、布局规范、模块、状态规范和样式规范。SMACSS也有一些推荐的命名规则,对于布局规范使用l-或者layout- 作为前缀;对于状态规范,使用is-hidden 或者is-collapsed 作为前缀。
相比OOCSS,SMACSS有了更多细节上的规范,但是CSS规则该划分为哪一类别的规范中,这是个需要仔细考虑的问题。后来出现的BEM对这一方面进行了改进,让它更易使用了。
BEM
BEM (块, 元素, 修饰符)是在2010年出现的规范,它的思想主要是围绕把用户界面切分成独立的块。块是一个可重用的组件(举个例子像表单搜索,可以这样定义
),元素是块的一部分不能单独重用(比如表单搜索中的button,),修饰符是定义了块或者元素外观、状态或者行为的实体(比如禁用搜索按钮,定义为)。BEM的规范很容易理解,对于新手来说命名规则上也很友好,缺点就是可能会导致class名字非常长,并且没有遵循传统的命名规范。后来出现的Atomic CSS又把这个非传统方式带到了一个新的高度。
Atomic CSS
Atomic CSS (也称为 功能性CSS)是2014年出现的一个规范,它的思想是基于可视化的方法创建小而功能单一化的class。这种规范与OOCSS、SMACSS和BEM完全相反——它并不是把页面上的元素看做是可重用的对象,Atomic CSS忽略掉了这些对象,每一个元素使用了可重用的单一功能的class样式集合。
因此像就被替换成这样的写法了
如果你看到这个例子第一反应是被吓的退缩了,没关系你并不是唯一有这想法的人——很多人认为这种方式完全违背了CSS的最佳实践,但是,关于这个有争议的规范在不同场景下的应用也产出了一系列精彩的讨论。这篇文章很清晰的分析了传统的分离思想是CSS依赖于HTML创建(即使使用像BEM这类的规范),而Atomic的方式是HTML依赖于CSS创建,两者都没错,但是仔细想想你会发现CSS和HTML彻底分离的想法是实现不了的。
其他的CSS设计模式,像CSS in JS其实也包含了CSS和HTML相互依赖的思想,这也成为了一个饱受争议的设计规范之一。
CSS in JS
CSS in JS 是2014年推出的一种设计模式,它的核心思想是把CSS直接写到各自组件中,而不是单独的样式文件里。这种方式在React框架中引入的,最早是使用内联样式,后来又进化成了使用JavaScript生成CSS然后插入到页面的style标签中的方式。
CSS in JS再一次违背了CSS中关于分离的最佳实践,主要原因是web随着时间推移发生了很大的变化。最初web大部分都是静态网站——这种情况下HTML内容和CSS表现分离是很有意义的,但现在大部分应用都是动态web构建——这种情况下可重用的组件更加有意义了。
五、水平居中、垂直居中、水平垂直居中
水平居中
子元素为行内元素还是块状元素,宽度一定还是宽度未定,采取的布局方案不同。下面进行分析:
- 行内元素:对父元素设置text-align:center;
- 定宽块状元素: 设置左右margin值为auto;
- 不定宽块状元素: 设置子元素为display:inline,然后在父元素上设置text-align:center;
- 通用方案: flex布局,对父元素设置display:flex;justify-content:center;
垂直居中
垂直居中对于子元素是单行内联文本、多行内联文本以及块状元素采用的方案是不同的。
- 父元素一定,子元素为单行内联文本:设置父元素的height等于行高line-height
- 父元素一定,子元素为多行内联文本:设置父元素的display:table-cell或inline-block,再设置vertical-align:middle;
- 块状元素:设置子元素position:fixed(absolute),然后设置margin:auto;
- 通用方案: flex布局,给父元素设置{display:flex; align-items:center;}
水平垂直居中
绝对定位解决方案
main{
position: absolute;
top: 50%;
left:50%;
margin-top: -3em;
margin-left: -9rm;
18em;
height: 6em;
}
使用CSS3的transform
main {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
Flexbox的解决方案
main {
display: flex;
align-items: center;
justify-content: center;
18em;
height: 10em;
}
position的解决方案 pc端最佳方案
main {
position: absolute;
top:0;
left:0;
right:0;
bottom:0;
200px;
height:200px;
margin:auto;
}