CSS宝典④-CSS布局秘籍(1)任督二脉BFC/IFC

image.png

HTML系列:

CSS系列:

01、CSS布局

1.1、正常布局流(Normal flow)

正常布局流 就是不做任何布局控制,按照HTML的顺序(从左到右,从上而下)进行布局排列。网页基于盒子模型进行正常的布局,主要特点:

  • 盒子布局:单个内容的布局,把内容放入盒子,加上盒子三件套(padding、boder、margin)。
  • 块盒子纵向布局:块级元素单独一行,按照顺序垂直排列,并按其margin分离。
  • 内联盒子水平布局:内联元素会在一行水平排列,高度、宽度都取决于内容,直到空间不足另起一行(换行)。高矮不齐,底部对齐。
  • 边距折叠:垂直相邻元素的垂直margin会保留最大的那一个,就是盒子的外边距折叠。
  • 空白折叠:无论多少个连续空格、换行、tab,都会折叠为一个空格。

块元素 行内元素
是否换行 独占一行,从新的一行开始,其后也另起一行 和其他行内元素在同一行
大小设置 元素的高、宽、行高、边距、对齐都可调整,宽度默认100% 元素高、宽、外边距不可设置,根据内容自适应
包含元素 一般可包含其他行内元素和块元素 一般可包含其他行内元素,不可包含块元素
常见元素 div,form、table,h1-h6,p,pre,ul/ol/li,dt/dl,hr,br span,font,input,textarea,label,img,a,button,select
盒子 块级盒子 (block box):应用完整的盒子模型 内联盒子 (inline box):部分盒子模型有效
  • 还有一种混合型“行内块元素”属于行内元素的一种,和其他元素在一行,但元素的高、宽、外边距都可以设置,如buttonimginput
  • 通过CSS样式的display属性可以更改元素的布局类型,如可设置<a>为一个块元素布局display: block;

标准布局总是这样从左到右、从上而下的顺序排列。但当我们要实现一些特殊的的布局效果时就没法了,这时的办法就是 —— 🚫脱离文档流

🚫脱离文档流,就是从正常文档流中移除,文档流布局就不考虑他了,也就不会占用空间。基本上可以这样理解,当然也不是绝对就没人管了,他的父容器还是管的,至于怎么管看《格式化上下文》。

常用的脱离文档流的方式:floatposition

  • float浮动,会使元素脱离文档流,移动到容器左/右边,后面元素会围绕浮动元素。
  • position定位,绝对定位(absolute)、固定定位(fixed),会使元素脱离文档流,空出来的位置被后续元素代替,所以会出现和其他元素重叠的问题。

1.2、display布局属性

正常流中的所有元素都有一个display的值,这个属性允许我们更改默认的显示方式。display用来设置多种布局方式,可让不同元素类型(行、块元素)转换。

属性/值 描述
display 设置元素显示类型,包括下面这些枚举值
 none 元素隐藏不显示,不占据空间、无交互,常用于隐藏元素
block 此元素将显示为块级元素
inline 内联,此元素会被显示为内联元素
inline-block 行内块元素(CSS2.1),介于内联和块之间,除了不换行,高宽、盒子三件套都有效。
常用<ul><li>+inline-block来实现导航
flex IE11 弹性盒子布局(横向布局),inline-flex 内联的弹性盒子
grid 非常灵活的网格布局,有些属性IE不支持。inline-grid 内联的网格布局
 list-item 此元素会作为列表,类似<ul>,父元素显示为 block 盒,内部变为多个 list-item inline
 table 表格布局,同家族还有个inline-table内联表格布局、table-row、table-cell
 contents 伪盒子,充当遮罩的元素,不会产生任何盒子(不会被渲染),但不影响其子元素的布局和渲染
 flow-root IE🚫 建立一个无副作用的BFC
<span style="display:block">span元素2</span>  <!--转换为块元素,类似一个div-->
<div style="display:inline">div元素</div> <!--转换为行内元素,类似一个span-->

02、什么是响应式布局?

2.1、响应式设计

响应式网页设计(responsive /rɪˈspɒnsɪv/ web design,RWD)指的是允许 Web 页面适应不同屏幕宽度等因素,进行布局和外观的调整的一系列实践。它涵盖了很多 CSS 和 HTML 的功能和技术,现在也基本是我们默认建设网站的方式。

image

如上图,基于媒体查询和现代布局,响应式设计成为当下的主流。通过媒体查询测试,针对不同的尺寸适配不同的CSS样式、图片,如调整字体大小、段落填充、菜单按钮布局、以及增大触摸按钮的大小等,让网页能够自适应各种设备尺寸、设备类型。

  • 响应式图形,创建多种尺寸版本文件,基于srcsetsizes,适配合适尺寸的文件。或者改用新的 <picture>元素。
<img srcset="elva-fairy-320w.jpg 320w,
    elva-fairy-480w.jpg 480w,
    elva-fairy-800w.jpg 800w" 
    sizes="(max-width: 320px) 280px,
    (max-width: 480px) 440px,
    800px"
    src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy">
  • 响应式排版,传统方式可以结合vw单位(视口的1%)、固定尺寸rem、px单位,现在可以基于媒体查询设置不同样式规则。
.p1 {
    font-size: calc(1rem + 2vw);
}
@media screen and (min-width:1440px) {
    .p1 {
        font-size: 150%;
    }
}
  • 视口元标签,明确视口的宽度为设备的宽度,并初始化缩放比例为1,建议添加如下元素申明。

<meta name="viewport" content="width=device-width,initial-scale=1">

2.2、@媒体查询

媒体查询是指针对不同的设备、特定的设备特征或者参数进行定制化的修改网站的样式,媒体查询的标准语法:

@media media-type and (media-feature-rule) { /* CSS规则 CSS rules go here */ }   /* 注意关键字and后面的空格 */

属性 描述 值/备注
@media 媒体查询申明
 media-type 媒体类型 - all:所有设备
- screen:屏幕,常用
- speech:语音合成器;print:打印,网页打印的时候
 逻辑操作符(and) 连接多个媒体查询语句 - and:查询条件都满足的时候才生效
- not:查询条件取反
- only:整个查询匹配的时候才生效,常用语兼容旧浏览器,使用时候必须指定媒体类型
- 逗号或者 or:查询条件满足一项即可匹配;
 media-feature-rule 媒体特征规则,一些条件表达式,常用尺寸判断 - min-width:>=最小宽度;max-width:<=最大宽度
- 更多媒体查询特征,如orientation(屏幕方向)
@import 导入外部css样式,支持媒体查询 @import url(example.css) screen and (width:800px);

image.png

/* 媒体查询:在大尺寸模式启用flex布局,横向排列 */
@media screen and (min-width: 40em) {
    .nav ul {
        display: flex;
    }
    .nav li {
        flex: 1;
    }
}

响应式布局-代码示例(Codepen)


03、CSS的格式化上下文

所有元素都是一个盒子Box,盒子Box是页面布局的基本单位,盒子的不同类型决定了他的布局方式。一个页面由各种盒子的组合、嵌套形成。这些盒子各不相同,有些是横排,有些竖排,有些是弹性,有些是网格,那他们是如何布局的呢?这就必须要了解的一个概念——格式化上下文

格式化上下文(Formatting Contexts),就是把页面内容分为多个不同的格式化上下文(区域),每个格式化上下文都是一个独立的渲染(布局)区域,存放同类型的盒子。根据盒子的不同,格式化上下文分为多种(四种)类型,每种类型有自己的渲染规则,决定了其内部子元素的定位、排列方式。

格式化上下文 简述
BFC块级格式化上下文 Block fomatting context ,由块级盒子组成的上下文区域,纵向排列。需要重点了解的,浮动float布局的各种坑就靠他来填了。
IFC内联级格式上下文 Inline formatting context,内联格式上下文,就是横向布局的内联盒子,由内联盒子构成
FFC:弹性盒格式化上下文 Flexible Formatting Contex,就是flex布局的弹性盒子,申明flex(或inline-flex)布局就是创建了一个FFC弹性盒子格式上下文。
GFC:网格格式化上下文 Grids Formatting Context,就是grid(或inline-grid)布局的盒子,二维网格布局,使用很方便。
不过由于兼容性问题(很多属性不支持IE),使用还不广泛,不过现代浏览器基本都支持了。

实际上这些格式上下文也是相互嵌套的,各自负责各自区域进行渲染(布局)。

image

上图仅为个人理解。


04、BFC-块级格式化上下文

Block fomatting context (= block-level box + Formatting Context),块级格式化上下文,简称 BFC。是一个独立的渲染(布局)区域,用于给块级盒子布局,包含的都是块级盒子。

🔸基本规则

  • 块级元素:首先BFC本身也是“块级盒子”(当然实际DOM中并没有这个盒子元素),其内部也都是块级元素盒子。
  • 独立主权:该区域的内部无论有什么东西、如何排列、在干什么,都不影响其外部,反之亦然。
  • 垂直排列:BFC内部的Box垂直排列,从上往下依次排列。
  • 垂直 margin 重叠:垂直方向间距由margin决定,同一BFC内相邻的Box的margin重叠,看谁的大就谁的。so,不是在同一个BFC则不会发生边距重叠。
  • 左边距,BFC中每个盒子,都是从其父容器Box的左边界开始,包括浮动元素也是这样。
  • 不会重叠:BFC区域不会与浮动盒子(float box)重叠,会向后找新的区域排列。注意❗,这是解决浮动盒子重叠的关键。
  • BFC高度:计算BFC高度时,会包含浮动元素(float box)。注意❗,这是解决高度坍塌、清除浮动的关键。

🔸如何触发BFC?

  • html 根元素,最大的BFC。
  • float 浮动:left、right,脱离了文档流,自成一派。自成一个独立BFC,它的内部是正常流布局。
  • position 定位:absolute、fixed,脱离了文档流,自成一派,同float浮动一样。
  • overflow 溢出,属性值不为 visible,常用 overflow: hidden 触发容器为BFC。
  • display 值:一个块级盒子,为独立BFC区域:
    • 行内块级盒子:inline-block
    • 表格类盒子:table、table-cell、table-caption、inline-table
    • 弹性盒子:flex 、inline-flex
    • 网格盒子:grid 、inline-grid

📢注意:上面这些场景会触发创建块格式化上下文,而不是这些盒子本身。

🔸使用场景

BFC主要还是浏览器用来渲染布局用的,在实际开发中可以利用他的这些规则做哪些事情呢?—— 处理浮动float布局的烂摊子!

image.png

① float导致的高度塌陷

❓ 问题:如果一个块级盒子如<div>中的元素都是float,他们都脱离了文档流,会导致盒子高度塌陷,就是高度没了。这时就会影响后面元素的布局了,造成不想看到的情景,float这个渣...

✅ 解决方法:触发这个容器的BFC,因为BFC在计算高度的时候会考虑内部的浮动元素,浮动元素本身也是一个独立BFC。

<div class="height-lose">
    <div>div1</div>
    <div>div2</div>
    <i>艰难的撑起了一点高度</i>
</div>
<style>
    .height-lose{
        border:2px solid;
        /* 建立BFC,防止高度塌陷 */
        overflow: hidden;
        /* display: table; */   /* 我也可以 */
    }
    .height-lose>div{
        float: left;
        height: 50px; width: 50px; margin: 5px;
        background-color: antiquewhite;                    
    }
</style>

» 父容器div的高度坍塌,因为没有计算浮动元素。触发父容器BFC即可解决

image.pngimage.png

② float导致的盒子重叠/环绕

❓ 问题:如下示例,父容器<div>中,左侧子元素是浮动float布局,导致后面正常元素与他重叠了,区域重叠,内容会绕开,看上去就是环绕效果。

✅ 解决方法:触发后面的的盒子为BFC,防止重叠,因BFC不会和其他浮动元素重叠。这种方法还可以用来实现左右两栏布局。

<div class="left-right">
    <div>left:左浮动box左浮动box</div>
    <div>right:我是右边,你挡着我了!我是右边,不是左边,不要挡到我。</div>
</div>
<style>
    .left-right div:first-of-type {
        float: left;
        width: 100px;
        background-color: #7F7;
    }
    .left-right div:last-of-type {
        width: 160px;
        background-color: #77FA;
        /* 右侧盒子触发BFC,防止被遮挡 */
        overflow: hidden;
        /* display: table; */    /* 我也可以 */
    }
</style>

» 盒子重叠,内容环绕,触发BFC解决

image.pngimage.png

③ 清除float浮动

由于浮动float会导致后续正常布局的元素布局“不正常”,主要原因就是浮动float盒子的父容器高度塌陷、元素重叠。因此解决方法也就是恢复其高度,触发其父元素的BFC即可,方法同上。

④ 边距重叠

❓ 问题:如下示例中,父容器<div>,两个子元素<p>的上下边距重叠了,有的时候这并不是希望看到的。

✅ 解决方法:原本这两个元素是在同一个BFC里,解决方式就是把一个<p>元素放到另一个BFC里,拆散他们!

<div class="margin-overlap">
    <p>p1:margin:30px 0</p>
    <div class="bfc">
        <p>p2:margin:30px 0</p>
    </div>
</div>
<style>
    .margin-overlap p {
        margin: 30px 0;
        padding: 0 10px;
        border: 2px solid skyblue;
        line-height: 30px;
        height: 30px;
    }
    .bfc {
        /* 建立BFC,就是要打破你们的水乳交融 */
        overflow: hidden;
        /* display:  table; */   /* 我也可以 */
    }
</style>

image.pngimage.png


05、IFC:内联级格式上下文

Inline formatting context ,内联级格式上下文,简称 IFC。包含行内元素盒子,从左到右横向排列成一行。形成条件比较简单,当块级元素中仅包含行内元素盒子时,就形成了一个IFC。很多时候都是浏览器自动用匿名块进行包装形成IFC,如当IFC中有块级元素插入时,会拆分产生两个IFC

基本规则

  • 水平排列:IFC内都是行内元素盒子,水平方向排列。
  • 垂直对齐vertical-align:底部、顶部对齐,或者文本基线,不同元素默认对齐方式不同。
  • 行框(line box):包含了一整行的行内盒子的矩形区域,被称为该行的行框(line box),宽度由内容决定,高度由CSS计算(最高的元素)。
  • 多行-多行框:当一个IFC的内容比较多,会自动换行,会切分为多个行框(line box)。
  • 水平间距:盒子之间水平margin、border、padding都有效,会推开其他盒子。
  • 水平对齐text-align:当内容宽度小于行框时,水平渲染规则由 text-align来决定。所以一般可以用text-align:center;来设置水平居中。
  • 垂直间距:会有用,但不会计算垂直的空间,不影响行高、不影响其他元素布局。
  • 默认有间隙:行内元素盒子之间有一个默认间隙。

image.png

<p>我只是路过而已!</p>
<div class="inline-box">
    <span>span:padding:100px</span>
    <img src="../res/qq.png" alt="图片" height="100px">
    <p>p标签,inline-block</p>
</div>
<p>我是新的一个p盒子内容,我只是路过而已,别当到我了!</p>
<style>
    .inline-box {
        text-align: center; /*水平居中*/
        background-color: aliceblue;
        height: 130px;
        /*line-height: 130px;*/  /* 基于line-height 垂直居中,子元素会继承*/
        /* overflow: hidden;  */ /* 隐藏溢出部分内容 */
    }
    .inline-box * {
        background-color: #F666;
        vertical-align: middle; /* 基于行框高度 垂直居中*/
    }
    .inline-box p {
        display: inline-block;
        margin: 0;
    }
    .inline-box span{
        margin: 300px 0; /*margin没有卵用,如果为inline-block有用*/
        padding: 100px 0;  /*padding 会溢出,不影响其他元素布局,会重叠*/
        border: 2px solid blue;
    }
</style>

» 垂直的padding有效,超出了父容器边界

image.png

» 启用注释代码:

image.png

⁉️上面的示例中可得出如下结论

  • 行框的高度由长得最高的元素撑起来的。
  • 垂直margin好像没什么用,paddingborder部分有效,不会计算垂直空间,不影响其他元素布局,但会影响渲染,有重叠。
  • text-align: center;,让行内元素水平居中布局显示。
  • vertical-align: middle;,可以让行内元素垂直居中显示(基于行框的高度,而不是父容器高度)。
  • line-height: 130px;,让行内元素基于line-height 垂直居中。

©️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀

posted @ 2022-11-07 09:42  安木夕  阅读(739)  评论(0编辑  收藏  举报