CSS进阶指南

尚衍亮 2019-06-26

一 前言

要想掌握CSS部分的内容其实并不容易,尽管你已经阅读过相当多的关于CSS的书籍,但是还是免不了去网上搜索相关的知识扩大你对CSS内容的掌握。在网络上查找最好的地方当然是CSS官网文档,不过英文版的官方文档将很大一部分人拒之门外,而中文版的博客上五花八门的只是零散又不权威,很容易将人带入歧途,浪费时间。笔者写这篇文章,摘录博客上总结的CSS知识,同时参考CSS官方文档,尽力保证其正确性。希望能节省开发者查阅的时间,提高效率。如有错误的地方,还请大家指出~一起学习,共同进步。

二 正文

1.DOM脱离文档流

脱离文档流的元素都是块级元素。
参考资料:
【1】https://www.cnblogs.com/chuaW...
(1)什么是文档流
指语言文本从左到右,从上到下显示,这是传统HTML文档的文本布局。
脱离文档流即是元素打乱了这个排列,或是从排版中拿走。

(2)什么情况下会脱离文档流
浮动(float)、绝对定位(absolute)、固定定位(fixed)三种方式定位会脱离文档流。

(3)浮动
浮动元素会脱离文档流并向左/向右浮动,直到碰到父元素或者另一个浮动元素。
float 属性定义元素在哪个方向浮动。以往这个属性总应用于图像,使文本围绕在图像周围,不过在 CSS 中,任何元素都可以浮动。浮动元素会生成一个块级框,而不论它本身是何种元素。如果浮动非替换元素,则要指定一个明确的宽度;否则,它们会尽可能地窄。
浮动元素脱离文档流:
1.没有实际高度,浮动会导致父元素高度坍塌
2.位置属性(left/top/right/bottom)是没有用的
需要注意:
浮动有点像玩俄罗斯方块。向左浮动,方块从右往左滑过来,如果某一行空间不够(基于父容器的宽度),那么这个块会沿着最右边的块的下边沿水平划过来,最后看卡到哪里就停止。
CSS进阶指南

left4在第一行left3后面宽度不够,换行成第二行。在left2后面宽度不够,只能在left1后面。right1自然是从第二行开始查找位置,很幸运第二行现在唯一的元素#left4右面空间足够,放置即可。right2在第二行中没有足够的位置,换行成第三行,找到空余位置插入。

(4)定位
关于定位的详细讲解请看这里:https://segmentfault.com/a/11...

//css中給元素设置position属性
el{
    position: absolute | fixed | relative | static | inherit
}

详解:
CSS进阶指南

position的值为absolute、fixed的元素脱离文档流,static、relative没有脱离文档流。

1.static定位不脱离文档流,设置left/top/right/bottom没有作用,对margin/padding敏感。
 2.对于外边距margin:块级元素的垂直相邻外边距会合并;
   而行内元素实际上不占上下外边距。行内元素的的左右外边距不会合并;
 3.浮动元素的外边距也不会合并。允许指定负的外边距值。(这里可以参考BFC部分)

对于浮动与定位的位置优先级:
  

(fixed == absolute) > float > relative > static。理解为同时设置了position:absolute和float:right。忽略float:right。

堆叠优先级:

定位元素z-index>=0时为(fixed == absolute == relative)  > static,z-index < 0时(fixed == absolute == relative)  < static。理解为兄弟元素一个设置了position:relative,另一个设置了position:static,当relative元素z-index为>=0时,无论static元素设置多少都在relative下面。如果relative设置z-index<0,则论static取什么值relative都会在static下面。

  定位元素z-index>=0时(fixed == absolute == relative)  > float,z-index < 0时(fixed == absolute == relative)  < float。理解为兄弟元素一个设置了position:relative,另一个设置了float:left,当relative元素z-index为>=0时,无论float元素设置多少都在relative下面。如果relative设置z-index<0,则无论float的z-index设置多少relative都会在float下面。

  float > static始终成立。因为z-index只有在定位元素上才起作用,定位元素包括fixed、absolute、relative。

  fixed == absolute == relative,比较堆叠顺序直接比较z-index大小即可。

2.垂直边距合并

参考资料:http://www.w3school.com.cn/cs...
当两个垂直外边距相遇时,它们将形成一个外边距。合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。

2.什么情况下会发垂直边距合并?
1)只针对块级元素
2)正常文档流

注意:合并行为只适用于外边距,如果元素有内边距和边框,它们绝对不会合并。

情况1:同一层级垂直方向上盒子的相遇

<html>
<head>

<style type="text/css">
* {
  margin:0;
  padding:0;
  border:0;
}

#d1 {
  width:100px;
  height:100px;
  margin-top:20px;
  margin-bottom:20px;
  background-color:red;
}

#d2 {
  width:100px;
  height:100px;
  margin-top:10px;
  background-color:blue;
}

</style>
</head>

<body>

<div id="d1">
</div>

<div id="d2">
</div>

<p>请注意,两个 div 之间的外边距是 20px,而不是 30px(20px + 10px)。</p>
</body>
</html>

CSS进阶指南

(注意:图片中的“内容区域”应该是包括content和padding)
demo1

情况2:存在嵌套关系
 父子节点都是没有脱离文档的两种定位(static、relative)的外边距(margin)会合并,显示效果以最大的那个外边距为准。

没有给父元素设置内边距或者有效的边框的情况下:

<html>
<head>
<style type="text/css">
* {
  margin:0;
  padding:0;
  border:0;
} 
#outer {
  width:300px;
  height:300px;
  background-color:red;
  margin-top:20px;
} 
#inner {
  width:50px;
  height:50px;
  background-color:blue;
  margin-top:10px;
}
</style>
</head>
<body>
<div id="outer">
  <div id="inner">
  </div>
</div>
<p>注释:请注意,如果不设置 div 的内边距和边框,那么内部 div 的上外边距将与外部 div 的上外边距合并(叠加)。</p>
<p>为父元素例子中的middle元素增加一个border-top或者padding-top即可</p>
</body>
</html>

CSS进阶指南

边距合并实际例子:

<!DOCTYPE html>
<html>
  <head>
      <meta charset="utf-8">
      <!--<script type="text/javascript" src='jquery-1.9.1.js'></script>-->
      <style>
    *{
      margin: 0;
      padding: 0;
      text-align: right;
      color: #FFF;
    }
    #container{
      position: absolute;
      left: 20px;
      margin-top: 10px;
      width: 600px;
      height: 600px;
      background-color: green;
    }
    #big{
      position: relative;
      left: 20px;
      margin-top: 40px;
      width: 300px;
      height: 300px;
      background-color: #000;
    }
    #normal{
      position: static;
      margin-left: 20px;
      margin-top: 50px;
      width: 200px;
      height: 200px;
      background-color: #aaa;
    }
    #middle{
      position: absolute;
      margin-left:0px;
      margin-top:20px;
      width: 100px;
      height: 100px;
      background-color: #333;
    }
    </style>
  </head>
  <body>
    <div id="container">
          <div id="big">
            <div id="normal">
              <div id="middle">
                middle</div>normal
              </div>big
            </div> container
      </div>
    </div>
</body>
</html>

CSS进阶指南

normal和big都没有脱离文档流,发生嵌套时,最终确认上边距为50px.

在包含块上设置边框或者内边距,会使其子元素的外边距包含在包含块内。《CSS权威指南》(第三版)
解决这种情况下边距合并:

<!DOCTYPE html>
<html>
  <head>
      <meta charset="utf-8">
      <!--<script type="text/javascript" src='jquery-1.9.1.js'></script>-->
      <style>
    *{
      margin: 0;
      padding: 0;
      text-align: right;
      color: #FFF;
    }
    #container{
      position: absolute;
      left: 20px;
      margin-top: 10px;
      width: 600px;
      height: 600px;
      background-color: green;
    }
    #big{
      padding-top:5px;
      position: relative;
      left: 20px;
      margin-top: 40px;
      width: 300px;
      height: 300px;
      background-color: #000;
    }
    #normal{
      position: static;
      margin-left: 20px;
      margin-top: 50px;
      width: 200px;
      height: 200px;
      background-color: #aaa;
    }
    #middle{
      position: absolute;
      margin-left:0px;
      margin-top:20px;
      width: 100px;
      height: 100px;
      background-color: #333;
    }
    </style>
  </head>
  <body>
    <div id="container">
          <div id="big">
            <div id="normal">
              <div id="middle">
                middle</div>normal
              </div>big
            </div> container
      </div>
    </div>
</body>
</html>

CSS进阶指南

注意:#big{ padding-top:5px;} 这里normal上边框距离big上边框的值应该是:margin-top(normal) + padding-top(big)

demo2

margin讲解
父元素的第一个子元素的上边距margin-top如果碰不到有效的border或者padding.就会不断一层一层的找自己“领导”(父元素,祖先元素)的麻烦。只要给领导设置个有效的 border或者padding就可以有效的管制这个目无领导的margin防止它越级,假传圣旨,把自己的margin当领导的margin执行。

对于垂直外边距合并的解决方案上面已经解释了,为父元素例子中的middle元素增加一个border-top或者padding-top即可解决这个问题。

情况3.外边距与自身发生合并

假设有一个空元素,它有外边距,但是没有边框或填充。在这种情况下,上外边距与下外边距就碰到了一起,它们会发生合并:
CSS进阶指南
如果这个外边距遇到另一个元素的外边距,它还会发生合并:
CSS进阶指南
这就是一系列的段落元素占用空间非常小的原因,因为它们的所有外边距都合并到一起,形成了一个小的外边距。

3.absolute定位结果

分两种情况来考虑:

第一种,元素的某条边没有设置定位属性(left/top/right/bottom)的时候,这一边就会将absolute块(包括外边距)按流式布局(正常布局)来排列,当然这个流式布局就会受到内边距padding的影响了。

<!DOCTYPE html>
<html>
  <head>
      <meta charset="utf-8">
      <!--<script type="text/javascript" src='jquery-1.9.1.js'></script>-->
      <style>
    *{
      margin: 0;
      padding: 0;
      text-align: right;
      color: #FFF;
    }
    #container{
      position: absolute;
      left: 20px;
      margin-top: 10px;
      width: 600px;
      height: 600px;
      background-color: green;
    }
    #big{
      position: relative;
      left: 20px;
      margin-top: 40px;
      width: 300px;
      height: 300px;
      background-color: #000;
    }
    #normal{
      position: static;
      margin-left: 20px;
      margin-top: 50px;
      width: 200px;
      height: 200px;
      background-color: #aaa;
    }
    #middle{
      position: absolute;
      margin-left:0px;
      margin-top:20px;
      width: 100px;
      height: 100px;
      background-color: #333;
    }
    </style>
  </head>
  <body>
    <div id="container">
          <div id="big">
            <div id="normal">
              <div id="middle">
                middle</div>normal
              </div>big
            </div> container
      </div>
    </div>
</body>
</html>

CSS进阶指南

第二种,元素的某条边设置了定位属性(left/top/right/bottom)的时候,这一边就会被作为脱离文档流的边来处理,会相对于 static 定位以外的第一个父元素(的边框)进行定位,如果这时候设置了外边距,那么这一边相对于基准元素的偏移=定位值(left/top/right/bottom)+ 外边距。

<!DOCTYPE html>
<html>
  <head>
      <meta charset="utf-8">
      <!--<script type="text/javascript" src='jquery-1.9.1.js'></script>-->
      <style>
    *{
      margin: 0;
      padding: 0;
      text-align: right;
      color: #FFF;
    }
    #container{
      position: absolute;
      left: 20px;
      margin-top: 10px;
      width: 600px;
      height: 600px;
      background-color: green;
    }
    #big{
      position: relative;
      left: 20px;
      margin-top: 40px;
      width: 300px;
      height: 300px;
      background-color: #000;
    }
    #normal{
      position: static;
      margin-left: 20px;
      margin-top: 50px;
      width: 200px;
      height: 200px;
      background-color: #aaa;
    }
    #middle{
      position: absolute;
      left:0px;
      margin-left:0px;
      margin-top:20px;
      width: 100px;
      height: 100px;
      background-color: #333;
    }
    </style>
  </head>
  <body>
    <div id="container">
          <div id="big">
            <div id="normal">
              <div id="middle">
                middle</div>normal
              </div>big
            </div> container
      </div>
    </div>
</body>
</html>

CSS进阶指南

注意:middle设置了left:0

同时,作为脱离文档流来处理的边是基于那个基准元素的边框来定位的,当然不受那个元素内边距padding的影响。

2.文档流与文本流是怎么回事?
相关问答:https://www.zhihu.com/questio...

3.BFC

BFC(Block Formatting Contexts)直译为”块级格式化上下文”。Block Formatting Contexts就是页面上的一个隔离的渲染区域,容器里面的子元素不会在布局上影响到外面的元素,反之也是如此。

BFC形成
float 的值不为 none
position 的值不为 static 或 relative
display属性为inline-boxs、table-cells、table-captions的不是块盒的块容器(除非这个值已经被传播到视口),
overflow不为visible的块盒才会为它的内容创建新的BFC。
body元素

BFC渲染规则(6条)
内部的Box会在垂直方向,一个接一个地放置。
Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
BFC的区域不会与float box重叠,常用来清除浮动和布局。
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
计算BFC的高度时,浮动元素也参与计算

4.IFC

IFC(Inline Formatting Contexts)直译为”内联格式化上下文”,IFC的line box(线框)高度由其包含行内元素中最高的实际高度计算而来(不受到竖直方向的padding/margin影响)

IFC渲染规则
框会从包含块的顶部开始,一个接一个地水平摆放。
摆放这些框的时候,它们在水平方向上的外边距、边框、内边距所占用的空间都会被考虑在内。在垂直方向上,这些框可能会以不同形式来对齐:它们可能会把底部或顶部对齐,也可能把其内部的文本基线对齐。能把在一行上的框都完全包含进去的一个矩形区域,被称为该行的行框。水平的margin、padding、border有效,垂直无效。不能指定宽高。
行框的宽度是由包含块和存在的浮动来决定。

IFC ‘line-height’ 与 ‘vertical-align’ 属性
计算行框里的各行内级框的高度。对于置换元素、行内块元素、行内表格元素来说,这是边界框的高度,对于行内框来说,这是其 ‘line-height’。
行内级元素根据其 ‘vertical-align’ 属性垂直对齐。在这些框使用 ‘top’ 或 ‘bottom’ 对齐的情况下,user-agent必须以最小化行框的高为目标对齐这些框。若这些框够高,则存在多个解而 CSS 2.1 不定义行框基线的位置。
行框的高是最顶端框的顶边到最底端框的底边的距离。

5.浮动与清除浮动

参考:
(1) w3School
(2)《CSS权威指南》(第三版)

5-1 浮动

5-2 清除浮动的最佳实践方案:

.clearfix:after {
     visibility: hidden;
     display: block;
     font-size: 0;
     content: " ";
     clear: both;
     height: 0;
}

6.margin:auto与width的计算

主要讲了margin与width结合处理大小为auto的问题,并详细介绍width的计算原则。
将这个问题之前先放一张盒模型示意图:

CSS进阶指南

现在有一个宽度为400px的包含块,针对如图所示:

CSS进阶指南

情况一:margin-left margin-right width的值都是auto
表 现:width尽可能的大,width的值为100%;margin-left margin-right均为0

情况二:margin-left margin-right width的值都是100
表 现:margin-right 被强制设置成200

情况三:margin-left margin-right 的值是auto;width已知为200px
表 现:居中显示

情况四:margin-left:-100, margin-right:100 width的值是auto
表 现:width被计算为400px

情况五:margin-left:100,width:100,margin-right的值都是auto
表 现:margin-right被计算为200px

三 后记

参考资料:

相关推荐

aSuncat / 0评论 2020-08-18