css知识梳理

578 阅读9分钟

CSS:

1:BFC

    Box是css布局的对象和基本单位。一个页面就是由Box组成的。元素的类型和display属性决定了Box的类型,有block-level box,有inline-level box,有run-in box。不同的box会参与到不同的Formatting Context中。
    Formatting-context格式化上下文,其实就是页面中的一块渲染区域,它有着一套渲染规则。规定了内部的元素是如何定位,以及和其他元素的关系和相互作用。常见的FC有BFC,IFC。
    BFC块格式化上下文,它规定了元素里的内容是如何布局定位,和其他元素的关系和相互作用。BFC提供了一个环境,当可视化布局的时候,里面的HTML元素按一定的规则进行布局。环境里面的元素不会影响到其他环境中的布局。  
    BFC的规则是box垂直从上向下排列;垂直方向的距离有margin决定(属于同一个BFC的两个相邻Box的margin会发生重叠,与方向无关);每个元素的margin box的左边与包含块的border box的左边相接触(从左往右的格式化,否则相反),浮动也是如此;和float元素的区域不重叠;它的高度包括内部浮动的子元素的高度;BFC是页面上一个隔离的独立容器,里面的元素如何布局都不会影响到外面。每个BFC都互相独立,互不影响。
    
    根元素,float元素,定位元素(position为absolute或者是fixed),overflow不为visible的元素,displayflex的元素,以及flex元素的子元素,行内块元素,表格元素,网格元素,displayflow-root的元素等这些会形成块格式化上下文。
    
    对于浮动定位以及清除浮动有作用,只会应用于同一个BFC中。    
        1:清楚元素内部浮动,计算BFC的高度时,浮动元素也参与计算。
        如父元素高度塌陷
        (父元素里面的子元素float后,父元素里如果没有内容,父元素的高度将为0,所以给父元素设置形成BFC后,父元素的高度就可以包括内部浮动子元素的高度,具体可以给父元素设置一个display:flex或overflow:hidden/auto;另外也可以使用伪类清除法去给父元素清除浮动)
        【清除浮动的几个tips:如何清除浮动:伪元素清除法;给父元素添加overflow:hideen属性,其实就是形成一个BFC;使用br标签,它有一个clear属性;使用一个空的div标签,加clear:both属性】
        2:防止垂直margin重叠,解决边距合并【上下边距合并,左右边距不会合并】
        Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。
        父子元素和兄弟元素都有可能出现margin合并。父元素和子元素的margin-top或margin-bottom合并,兄弟元素中,下面元素的margin-top和上面元素的margin-bottom合并
        按照BFC的定义,只有同属于一个BFC时,两个元素才有可能发生垂直Margin的重叠,这个包括相邻元素,嵌套元素,只要他们之间没有阻挡(例如边框,非空内容,padding等)就会发生margin重叠。
        因此要解决margin重叠问题,只要让它们不在同一个BFC就行了,但是对于两个相邻元素来说,意义不大,没有必要给它们加个外壳,但是对于嵌套元素来说就很有必要了,只要把父元素设为BFC就可以了。这样子元素的margin就不会和父元素的margin发生重叠了。[链接](https://juejin.cn/post/6844903544726749198)
        
        3:不和浮动元素重叠,即BFC的区域不和浮动元素的区域重叠。可以解决自适应宽度(用float+div做左右适应布局),左右两个div,左边div宽度固定,左浮动,右边div自适应宽度,overflow:auto即可或右边div的display设为flex。(当然该布局有多种方式,比如绝对定位加上margin。如下:
      <!doctype html>
        <html lang="en">
        <head>
          <meta charset="UTF-8">
          <meta name="viewport"
                content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge">
          <title>居中Document</title>
          <style>
            *{
              margin:0;
              padding:0;
              box-sizing: border-box;
            }
            .container>div{
              border:2px solid red;
            }
            .left{
              height:150px;
              width:200px;
             position:absolute;
              top: 0;
              left:0;
            }
            .right{
             margin-left:200px;
              height:150px;
              /*width:100%;//可不能设置width是100%*/
              /*overflow:auto;*/
              /*      display:flex;*/
            }
          </style>
        </head>
        <body>
        <div class="container">
          <div class="left">left</div>
          <div class="right">right
            right<br>
            right<br>
            right<br>
            right<br>
          </div>
        </div>
        </body>
        </html>)
                    

布局:

如何实现一个三栏布局,左右宽度固定,中间宽度自适应。

1:绝对定位,中间主体用左右 margin 撑开
2:自身浮动法,中间的 div 要放在最后,注意清除浮动
3margin 负值法:左右两栏均左浮动,左右两栏采用负的 margin 值。中间栏被宽度为 100%的浮动元素包起来。左右两栏 div 的顺序不分先后,但是主体部分 div 要放前面。
4flex 布局,左右 flex-basis,中间 flex-grow

圣杯布局和双飞翼布局

 圣杯布局和双飞翼布局基本上是一致的,都是两边固定宽度,中间自适应的三栏布局,其中,中间栏放到文档流前面,保证先行渲染。解决方案大体相同,都是三栏全部float:left浮动,区别在于解决中间栏div的内容不被遮挡上,圣杯布局是中间栏在添加相对定位,并配合leftright属性,效果上表现为三栏是单独分开的(如果可以看到空隙的话),而双飞翼布局是在中间栏的div中嵌套一个div,内容写在嵌套的div里,然后对嵌套的div设置margin-leftmargin-right,效果上表现为左右两栏在中间栏的上面,中间栏还是100%宽度,只不过中间栏的内容通过margin的值显示在中间。

圣杯布局的关键点在于:

center放在文档流前面以便于优先渲染
使用负外边距
left使用相对定位

圣杯布局思路: 1》container里面的三个div,设置它们的宽度,middle是自适应,所以宽度为100%。left和right我们分别设为300px和200px。由于div元素,所以它们就会从上到下依次排列,middle在最上面。 2》我们想让然后让这三个div浮动float:left;此时设置了浮动后,元素会脱离文档流,所以也不要忘了清除浮动,给父元素container添加一个overflow:hidden的属性。由于middle的宽度是100%{该地方一定要加宽度100%,因为middle元素设置了浮动。

浮动元素,由于浮动具有包裹性,在不显式设置宽度的情况下会自动“收缩”到内容的尺寸大小。如果去掉width: 100%,则当中间栏不包含或者包含较少内容时,整个布局会“崩掉”},所以left和right会在第二行显示,就是这个样子《我这里加了边框,方便看效果》 3》我们要让其在一行显示,利用margin-left负边距去做到,给left设置margin-left:-100%,给right设置margin-left:-200px《right的负margin值是自身的宽度》 4》这样设置以后,虽然在一行了,但是是有问题的。left和main有重叠,right也和main有重叠。

此时我们就想到用padding或者margin去实现。圣杯布局采用的就是padding,而双飞翼布局采用的是margin

5.1》圣杯布局:设置container的padding-left和padding-right分别为300px和200px;目的是腾出位置,此时页面是这样的 最后给left和right一个相对定位;设置left定位相对定位,且left为-300px(自身宽度的负值);right也为相对定位,left为200px即自身的宽度。最后: 代码:
.container{ overflow: hidden; padding:0 200px 0 300px; /min-width:800px;/ } .container>div{ height:50px; } .middle{ float:left; width:100%; border:2px solid green; } .left{ width:300px; float: left; border:2px solid red; margin-left:-100%; position: relative; left:-300px;

        }
        .right{
          width:200px;
          float: left;
          border:2px solid black;
          margin-left:-200px;
          position: relative;
          left:200px;
        }
      </style>
    </head>
    <body>
    <!--圣杯布局-->
    <div class="container">
      <div class="middle">MIDDLE</div>
      <div class="left">LEFT</div>
      <div class="right">RIGHT</div>
    </div>
    </body>

但是要注意,上面的布局有问题,当页面宽度变小的时候,由于元素是浮动的,布局就会乱掉。所以我们最好给container加一个最小宽度,它的值为left.width*2+right.width。为什么呢?简单的说就是由于设置了相对定位,所以当left原来的位置和right的位置产生重叠时,由于浮动原因一行放不下就会换行。所以布局就被打乱了,使用双飞翼布局就可以避免该问题。

5.2》双飞翼布局:使用margin属性。此时把页面结构稍微做下调整:

    <body>
    <!--双飞翼布局-->
    <div class="container">
      <div class="middle">
      	<div class="middleContent">MIDDLE</div>//注意我们在middle的里面又嵌套了一个div
      </div>
      <div class="left">LEFT</div>
      <div class="right">RIGHT</div>
    </div>
    </body>

此时将div.middleContent设置margin-left:300px,margin-right:200px。就可以实现效果了。

代码:

 <style>
    .container{
  overflow: hidden;
  /*padding:0 200px 0 300px;*/
  /*min-width:800px;*/
}
.container>div{
  height:50px;
}
.middle{
  float:left;
  width:100%;
  border:2px solid green;

}
.middleContent{
  margin:0 200px 0 300px;
}
.left{
  width:300px;
  float: left;
  border:2px solid red;
  margin-left:-100%;
  /*position: relative;*/
  /*left:-300px;*/

}
.right{
  width:200px;
  float: left;
  border:2px solid black;
  margin-left:-200px;
  /*position: relative;*/
  /*left:200px;*/
}
  </style>
</head>
<body>
<!--圣杯布局-->
<div class="container">
  <div class="middle">
    <div class="middleContent">MIDDLE</div>
  </div>
  <div class="left">LEFT</div>
  <div class="right">RIGHT</div>
</div>
</body>

可以看到,我们在middle里面又加了一个内容层。如果知道盒子模型,就知道我们是不能直接给middle添加margin属性,因为我们已经设置div.middle的width是100%,再设置margin的话,就会超过窗口的宽度,所以我们再创造一个内容层,将div.middle里所有要显示的内容放到middleContent里,给middleContent设置margin就行了。

圣杯布局和双飞翼布局的理解和区别

浅谈面试中常考的两种经典布局——圣杯与双飞翼

为什么不使用绝对定位去布局,因为绝对定位的话,当左右的div高度大于middle的高度时,由于绝对定位,它就脱离了文档流,container的高度包不住定位了的元素,导致下面的footer会被绝对定位了的元素覆盖。

平均布局:float+负margin

关于垂直居中: 1:如下图所示,想要实现水平垂直居中,分两种情况,元素是否固定宽高

1.1》元素固定宽高
absolute + 负margin		《给要居中的元素设置	   position:absolute,top:50%,left:50%,margin-top:负自身高度的一半,margin-left:负自身宽度的一半》
absolute + margin auto	 《给要居中的元素设置		position:absolute,top:0,left:0,bottom:0,right:0,margin:auto负自身高度的一半,margin-left:负自身宽度的一半》
absolute + calc			 《给要居中的元素设置		position:absolute,top:calc(50%-自身高度的一半),left:calc(50%-自身宽度的一半)》

1.2》居中元素不定宽高
absolute + transform     《给要居中的元素设置		position:absolute,top:50%,left:50%,transform:translate(-50%,-50%)》
lineheight				《给要居中的元素的父元素设置 lineheight:自身的高度,text-align:center,要居中的元素display:inline-block,lineheight:initial,vertical-align:middle,
table                    《给要居中的元素父元素设置text-align:center,要居中的元素设置display:inline-block	table本身就会让元素垂直居中	》
css-table 			     《给要居中的元素的父元素设置 display:table-cell,text-align:center,vertical-align:middle,要居中的元素设置display:inline-block
要居中的元素:display:inline-block》
flex                     《给要居中的元素的父元素设置 display:felx,justify-content:center,align-items:center》
grid                     《给要居中的元素的父元素设置 display: grid;要居中的元素:align-self: center; justify-self: center;

具体可参考实现水平垂直居中