随手记六——两个经典BUG和bfc

两个经典BUG:
1、margin塌陷(父子级之间):垂直方向的margin,父子元素是结合在一起的,它俩会取最大的值,父子一起移动。意思就是,现有一个父级wrapper和子级box,wrapper有一属性margin-top:100px;父子一起垂直方向移动,这时给box加一个margin-top:50px;并不会使box在wrapper里面的位置移动,还是跟之前一样,只有在box的margin-top:150px;时才会移动,而且是带着父级wrapper一起移动。这就是选取两个margin-top中最大值导致的效果。相当于这个父级wrapper没有顶棚。
    解决方法:既然父级wrapper没有顶棚,那就给它加一个呗,给父级wrapper加一个属性border-top:1px solid red;这个时候子级box的margin-top就生效了。但是!这种方法并不聪明,因为加了个边不好看,而且在编程手法上不太专业。专业上,我们采用的是bfc(block format context块级格式化上下文)。
    bfc:css把html里的每一个元素都当作是一个盒子,而且进一步认为每一个盒子都有一套渲染规则,渲染规则就是说,写完这个代码,它能按照代码把这个东西绘制出来,每一个盒子都有一套一模一样的渲染规则,像是细胞里的基因一样。bfc就是通过某种手段,让其中一个或者多个盒子的渲染规则发生改变。触发bfc后,盒子会遵循另一套语法规则。
    如何触发一个盒子的bfc:position:absolute;    display:incline-block;    float:left/right;    overfloat:hinden;
    position:absolute;上面见过,将一个盒子变到另一个层面
    display:incline-block; 将盒子变成会行级块元素
    float:left/right;
    overfloat:hidden;  将溢出盒子部分隐藏
 
先来了解一下overfloat:hidden;
这是初始的样子,这时候将content的margin-left改成75px;就有如下绿色部分溢出
再给wrapper加上overfloat:hidden;就有如下,溢出部分被隐藏
回到正题,解决margin塌陷的问题,overfloat:hidden;是第一个解决方案。将margin-left恢复到50px;再加上一个margin-top:50px;你就惊奇发现!有!效!果!
 
 
第二个方案,使用display:incline-block;得到一样的效果
第三个方案:使用position:absolute;同样的效果
第四个方案:float:left/right;也一样。
 
但是,无论是哪一个方案,都不能完美解决margin塌陷问题,因为,解决了一个问题又会面临别的新问题,比如说,我的设计中就是需要有溢出部分,那这时用overfloat:hidden;来解决塌陷就很不OK,这时候我们可以从另外几个方案中选择最不受影响的方法来解决margin塌陷就好。
 
2、margin合并(兄弟级之间):在div里,两个兄弟级的div之间往往也存在margin问题,比如说:
box1和box2两个span之间,margin-right和margin-left都能起作用,而demo1和demo2两个div的margin-top和margin-bottom则只能取其最大值起作用。这种情况下,使用bfc同样能搞掂它,demo1或demo2或两个都安排一个position:absolute;这样就能起作用了。
 
3、关于margin塌陷和margin合并之间的对比:处理margin塌陷只需要在父级加css没改html,处理margin合并的时候除了加css还必须在上面加一层html。对于一个页面来说,html就是结构,css是装饰,修改一个html可能会对其他结构和css产生很大的影响,所以我们不能为了解决一个BUG而随意加一个没有意义的结构,这在开发中是绝对不被允许的。所以使用中如果遇到margin合并问题,我们不解决,我们可以通过数学的方法来弥补这个BUG,也就是说,那我兄弟级之间margin-top和margin-bottom取一个,通过调整数值来实现我们想要的效果。
 
 
float:left/right;一个看起来很厉害的元素。
浮动元素:浮动元素产生了浮动流,所有产生了浮动流的元素,块级元素看不到他们,但是产生了bfc的元素、文本类属性的元素(inline)以及文本都能看到浮动元素。 (这也是它和position:absolute的区别,它不是分层的)
试试效果:先建立这么个东西,可以看到div遵循它以往的规则,每个都独占一行。
 
这个时候我给它加一个float:left;就发现它们不占一行了,开始站队了,顺序是从左往右的。
再试试float:right;发现这下子是从右往左了。
多搞几个div试试,发现float的站队是按行来的。
给它加一些普通的规则,比如说margin-top:5px;和margin-left:5px;就有下图,看来一行能放多少个也要看父级这个框有多宽嘛。
弄好看点,把宽加大,嘿嘿,是不是有点眼熟??好多页面也有这种类似的结构。

 

 

接下来把它还原到最开始的样子,并把父级box的宽高去掉,变成自适应的类型。就发现,这个父级box的边框并不能被撑大,这就是因为前面说到的,浮动流元素并不能被块级元素识别到,所以在作为块级元素div的box来说,它里面没有元素。
浮动流元素在作用的时候,会在逻辑上产生浮动流,让块元素无法识别到它,但相应的,我们也有一个clear:left/right/both;属性来清除浮动流(一般情况下都用both),在这里使用<p>元素来清除浮动流,因为<p>是文本类元素,可以识别浮动流元素滴。
然后就有上面的效果啦,这个box框被撑开啦!然后将这个p标签的边框去掉..就有下图,再来n个,就有下下图
 
以上是解决包裹浮动元素的一种方法,但在实际开发中并不这么使用,因为前面说过,不能为了解决一个问题而随意增加没有必要的结构。想要达到包裹浮动元素的效果又不增加结构,还有另外两种方法。
第一种是使用伪元素(绝大多情况下用这种)
使用伪元素清除浮动流要注意的是,一定要使用display:block;因为clear只能清除块级元素的浮动流。
第二种是利用别的能看到浮动流的元素
    给父级元素触发bfc,比如说增加属性float:left; position:absolute;之类的,这样父类就可以识别到浮动流,从而包裹住浮动流。但是有一点不一样,这次框框右边是贴着浮动元素的。
(拓展:凡是设置了position:absolute;float:left/right;系统对打内部把元素转换成行级块元素)
posted @ 2020-09-27 17:31  zher_leon  阅读(169)  评论(0编辑  收藏  举报