1 flex弹性布局

Flex布局的目标是提供一种更有效的方式来布局、对齐和分配容器中子元素的空间,即使它们的大小是未知的或动态的

flex布局背后的主要想法是让容器能够改变其内部元素的宽度/高度(和顺序),来更好地填充可用空间(主要是适应各种显示设备和屏幕大小)。即或将物品展开以填满可用的空闲空间,或将物品缩小以防止溢出。

最重要的是,flexbox布局与常规布局不同,是方向无关的(区块是基于垂直的,内联是基于水平的)。

注意:Flex布局最适合组件和小规模布局,而Grid布局则适合更大规模的布局。

flex属性按作用范围分为container和items两类

1.1 container

  • display:flex:定义容器为flex布局
  • flex-direction:规定flex容器主轴方向,默认为row
    • row|row-reverse|column|column-reverse
  • flex-wrap:允许换行,默认为nowrap(因为默认情况下,子项总是挤在同一行,即子项宽度定义无效)
    • nowrap|wrap|wrap-reverse
  • flex-flow:前两者的简写形式
    • flex-flow:column wrap
  • justify-content:规定主轴方向的排列形式

image-20211009142422206

  • align-items:规定元素垂直轴方向的排列形式

image-20211009142607363

  • align-content:当垂直轴上有额外的空间且元素大于一行时,规定全体元素在垂直轴上的排列方式,类似于justify-content在主轴上对齐单个元素。

image-20211009142722383

  • gap,row-gap,column-gap:指定元素间最小间距,当space过大时,定义gap是不起作用的

1.2 items

  • order:默认情况下,items按源顺序排列。order属性可以控制它们在容器中的顺序,默认为0
  • flex-grow:定义元素在空间足够时自动放大的比例(可以用来自动填满剩余空间),默认为0
  • flex-shrink:定义元素在空间不足时自动收缩的比例,默认为1
  • flexflex-growflex-shrinkflex-basis的简写,默认值为0 1 auto,后两个参数是可选的
  • align-self:单独定义元素在垂直轴方向的排列形式,同align-items

1.3 align-items与align-content区别

条件 属性(是否有效果)
items container align-items align-content
单行 不指定高度
固定高度 否(当设置flex-warp:warp时,有效果)
多行 不指定高度
固定高度
  1. align-items属性是针对单独的每一个flex子项起作用,它的基本作用单位是每一个子项,在所有情况下都有效果
  2. align-content属性是将flex子项作为一个整体起作用,它的基本作用单位是子项构成的行,只在两种情况下有效果:
    1. 子项多行且指定flex容器高度
    2. 子项单行,指定flex容器高度且设置了flex-wrap:warp

2 grid栅格布局

CSS Grid Layout是一种基于二维网格的布局系统,是第一个专为解决布局问题而发明的CSS模块

grid属性按作用范围分为grid container和grid items两类

2.1 grid container

  • display: grid | inline-grid:定义容器为grid或inline-grid布局

  • grid-template-columns | grid-template-rows:定义网格的行与列,可以是长度,也可以是百分数或者fr

    • 定义重复的部分,可以使用repeat关键字,例如repeat(3,20px),等同于20px 20px 20px
    • fr表示将区间按比例设置为容器空闲空间(去掉指定px的部分)的一部分。例如,这将把每个项目设置为网格容器宽度的三分之一:1fr 1fr 1fr
  • grid-template-areas:通过引用由grid-area属性指定的网格区域的名称来定义网格模板。重复网格区域的名称会导致内容跨越这些单元格。.表示空单元格,none表示不定义此区域。语法本身提供了网格结构的可视化。

    •  1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      
      .item-a {
        grid-area: header;
      }
      .item-b {
        grid-area: main;
      }
      .item-c {
        grid-area: sidebar;
      }
      .item-d {
        grid-area: footer;
      }
      .container {
        display: grid;
        grid-template-columns: 50px 50px 50px 50px;
        grid-template-rows: auto;
        grid-template-areas: 
          "header header header header"
          "main main . sidebar"
          "footer footer footer footer";
      }
      

      image-20211020104943021

  • grid-template:在单个声明中设置rows、columns和areas的简写。例如

    • 1
      2
      3
      4
      5
      6
      
      .container {
        grid-template:
          "header header header" 25px 
          "footer footer footer" 25px 
          / auto 50px auto;
      }
      

      等价于

      1
      2
      3
      4
      5
      6
      7
      
      .container {
        grid-template-rows: 25px 25px
        grid-template-columns: auto 50px auto;
        grid-template-areas: 
          "header header header" 
          "footer footer footer";
      }
      
  • column-gap | row-gap | grid-column-gap | grid-row-gap:指定内部间隙宽度,例如:

    • 1
      2
      3
      4
      5
      6
      
      .container {
        grid-template-columns: 100px 50px 100px;
        grid-template-rows: 80px auto 80px; 
        column-gap: 10px;
        row-gap: 15px;
      }
      

      image-20211020105712423

  • gap | grid-gap:定义间隙的简写,写法为<row-gap> <column-gap>

  • justify-items:对每个区域内的网格项沿主轴方向进行排列,选项有start|end|center|stretch,单独调整某个网格项可使用justify-self属性

    • start:

    image-20211020132049623

    • end:

    image-20211020132139117

    • center:

    image-20211020132202229

    • stretch:

    image-20211020132230181

  • align-items:对每个区域内的网格项沿垂直轴方向进行排列,选项有start|end|stretch|center,单独调整某个网格项可使用align-self属性

    • 示例效果同上,自行脑补
  • place-itemsjustify-itemsalign-items的简写,例如place-items: center | end

  • justify-content:当网格的总尺寸小于容器的尺寸时(例如全部用px定义网格尺寸),可以使用此属性定义网格整体沿容器主轴方向的排列方式。选项有start|end|stretch|center|space-around|space-between|space-evenly

    • start:

    image-20211020133418836

    • end:

    image-20211020133457894

    • center:

    image-20211020133536716

    • stretch:

    image-20211020133717096

    • space-around:

    image-20211020133817641

    • space-between:

    image-20211020133908188

    • space-evenly(间隔宽度相等):

    image-20211020134016331

  • align-content:当网格的总尺寸小于容器的尺寸时(例如全部用px定义网格尺寸),可以使用此属性定义网格整体沿容器垂直轴方向的排列方式。选项有start|end|stretch|center|space-around|space-between|space-evenly

    • 效果同上,自行脑补
  • grid-auto-flow:划分网格以后,容器的子元素会按照顺序,自动放置在每一个网格。默认的放置顺序是"先行后列",即先填满第一行,再开始放入第二行。这个属性由grid-auto-flow确定,默认为row

    • column:表示从第一列开始,按从上到下的顺序依次填充。
    • row-dense:表示“先行后列”,并且尽可能紧密填满,尽量不出现空格
    • column-dense:表示“先列后行”,并且尽可能紧密填满,尽量不出现空格

2.2 grid items

  • grid-column-start | grid-column-end | grid-row-start | grid-row-end:指定网格项的占位标识,允许数字、线名、span等值,例如

    1
    2
    3
    4
    5
    6
    
    .item-b {
      grid-column-start: 1;
      grid-column-end: span col4-start;
      grid-row-start: 2;
      grid-row-end: span 2;
    }
    

    image-20211020142323770

  • grid-column | grid-row:以上属性的简写。示例:

    1
    2
    3
    4
    
    .item-c {
      grid-column: 3 / span 2;
      grid-row: third-line / 4;
    }
    

    image-20211020142457783

  • grid-area:以上所有的简写,示例:

    1
    2
    3
    
    .item-d {
      grid-area: 1 / col4-start / last-line / 6;
    }
    

    image-20211020142730561

  • justify-self:定义当前网格项内容在网格内部的沿主轴的排列方式,选项有start|end|center|stretch

  • align-self:定义当前网格项内容在网格内部的沿垂直轴的排列方式,选项有start|end|center|stretch

  • place-self:以上两项属性的简写,例如place-self: center end

3 面试常考布局

3.1 三栏布局

image-20211119134039191

3.1.1 float浮动实现

从左至右三部分的float属性分别设置为left、left、right,中间部分的宽度使用calc函数计算(100%-side宽度*2)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>三栏布局-float</title>
    <style>
        .container {
            width: 100%;
            min-width: 600px;
            height: 100vh;
        }
        .side {
            width: 200px;
            height: 100%;
            background-color: #60546b;
        }
        .main {
            height: 100%;
            width: calc(100% - 400px);
            background-color: bisque;
        }
        .left {
            float: left;
        }

        .right {
            float: right;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="side left"></div>
    <div class="main left"></div>
    <div class="side right"></div>
</div>
</body>
</html>

3.1.2 position定位实现

父相对,子绝对,定义各元素的left和right属性值即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>三栏布局-positoin</title>
    <style>
        .container {
            /*这里设置高度为100%是不生效的,因为100%是相对于父元素的,而body和html元素的高度默认为autp*/
            /*可以先将body和html元素的高度设置为100%*/
            height: 100vh;
            width: 100%;
            position: relative;
        }
        .side {
            position: absolute;
            width: 200px;
            height: 100%;
            background-color: bisque;
        }
        .main {
            position: absolute;
            height: 100%;
            left: 200px;
            right: 200px;
            /*也可以使用calc函数计算width*/
            /*left: 200px;*/
            /*width: calc(100% - 400px);*/
            background-color: #60546b;
        }
        .left {
            left: 0
        }
        .right {
            right: 0
        }
    </style>
</head>
<body>
<div class="container">
    <div class="side left"></div>
    <div class="main"></div>
    <div class="side right"></div>
</div>
</body>
</html>

3.1.3 flex布局实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>三栏布局-flex</title>
    <style>
        .container {
            display: flex;
            width: 100%;
            height: 100vh;
        }
        .side {
            width: 200px;
            height: 100%;
            background-color: bisque;
        }
        .main {
            flex: 1;
            background-color: #60546b;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="side"></div>
    <div class="main"></div>
    <div class="side"></div>
</div>
</body>
</html>

3.1.4 table布局实现

利用display属性的table结合table-cell,实现三栏布局

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>三栏布局-table</title>
    <style>
        .container {
            display: table;
            height: 100vh;
        }
        .side {
            height: 100%;
            width: 200px;
            background-color: #60546b;
        }
        .main {
            display: table-cell;
            width: 100%;
            height: 100%;
            background-color: bisque;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="side"></div>
    <div class="main"></div>
    <div class="side"></div>
</div>
</body>
</html>

3.1.5 grid布局实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .container {
            display: grid;
            grid-template-rows: 100vh;
            grid-template-columns: 200px auto 200px;
        }

        .side {
            background-color: #60546b;
        }

        .main {
            background-color: bisque;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="side"></div>
    <div class="main"></div>
    <div class="side"></div>
</div>
</body>
</html>

3.2 圣杯&双飞翼布局

  • 圣杯布局是讨论「三栏液态布局」的实现,它最早出自于谁或许不得而查了,但最早的完美实现是来自于 Matthew Levine 于2006年在「A LIST APART」上写的一篇文章,它主要讲述了网页中关于最佳圣杯的实现方法。

所谓液态布局是相对固态布局而言的,固态布局就是固定值不变的布局,液态就好比在容器里到了一杯水,它可以随着容器宽度的变化而自适应宽度。

  • 在这篇文章中,作者指出了当时的一些实现方式所存在的问题,如:必须按照源顺序(在 DOM 中表现为先写 Left,然后 Middle,最后,Right)等,它将可能导致代码不够灵活,尤其是从 DOM 的载入顺序上来说,中间的内容不能被首先加载。

  • 因此他给出一个方案,它将:

    1. 两边栏固定,中间自适应
    2. 允许中间一栏最先出现
    3. 允许任意一栏放在最上面;
    4. 仅需一个额外的 div 标签
    5. 仅需非常简单的 CSS,带上最少的兼容性补丁
  • 过程:

    • 先写header、container、footer三个div,并将三栏放入container中,其中,center部分写在最前面

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      
      <body>
      <div id="header">#header</div>
      
      <div id="container">
          <div id="center" class="column">#center</div>
          <div id="left" class="column">#left</div>
          <div id="right" class="column">#right</div>
      </div>
      
      <div id="footer">#footer</div>
      </body>
      
    • 为元素添加基本样式。由于container设置了内边距,因此中间栏看起来就处在了网页的中间,但左右两栏由于排在中间栏的后面,且因为空间不够被挤到了中间栏的下面

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      
      #container .column {
        float: left;  /* 三栏均向左浮动 */
      }
      #container {
        /* 将内边距设置为左右两栏的宽度 */
        padding-left: 200px;
        padding-right: 150px;
      }
      #center {
        width: 100%;  /* 基于父容器container的宽度 */
      }
      #left {
        width: 200px;  /* LC width */
      }
      #right {
        width: 150px;  /* RC width */
      }
      #footer {
        clear: both;	/* 清除 footer 的上下文环境,以免跟上面三栏一起浮动 */
      }
      
    • 调整左右两栏的位置

      • 首先,我们先将左侧栏的外边距设置为 -100%,这样一来,由于浮动的关系,左侧栏就能上位,与中间栏交叠在一起,并占据了左边。而右侧栏由于左侧栏的上位,自动向前浮动到了原来左侧栏的位置。
      • 接着我们要用到相对定位属性(relative),并设置一个与左侧栏等宽的偏移量
      • 右侧同理,不过不需要设置右偏移了
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      
      #container .columns {
        float: left;
        /* 利用相对定位调整位置 */
        position: relative;
      }
      #left {
        width: 200px;        /* LC width */
        margin-left: -100%;  
        right: 200px;        /* LC width */
      }
      #right {
        width: 150px;          /* RC width */
        margin-right: -150px;  /* RC width */
      }
      
    • 完整代码

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>圣杯布局</title>
          <style>
              #container .column {
                  float: left;
                  position: relative;
              }
              #container {
                  padding-left: 200px;
                  padding-right: 150px;
              }
              #center {
                  background-color: red;
                  width: 100%; /*基于父容器container的width*/
              }
              #left {
                  right: 200px;
                  margin-left: -100%;
                  background-color: orange;
                  width: 200px;
              }
              #right {
                  margin-right: -150px;
                  background-color: yellow;
                  width: 150px;
              }
              #footer {
                  clear: both
              }
          </style>
      </head>
      <body>
      <div id="header">#header</div>
      
      <div id="container">
          <div id="center" class="column">#center</div>
          <div id="left" class="column">#left</div>
          <div id="right" class="column">#right</div>
      </div>
      
      <div id="footer">#footer</div>
      </body>
      </html>
      

      image-20211122104411168