flex 弹性布局

认识 flexbox

  • Flexbox 翻译为弹性盒子:
    • 弹性盒子是一种用于按行或按列布局元素的一维布局方法 ;
    • 元素可以膨胀以填充额外的空间, 收缩以适应更小的空间;
    • 通常我们使用 Flexbox 来进行布局的方案称之为 flex 布局(flex layout);
  • flex 布局是目前 web 开发中使用最多的布局方案:
    • flex 布局(Flexible 布局,弹性布局);
    • 目前特别在移动端可以说已经完全普及;
    • 在 PC 端也几乎已经完全普及和使用, 只有非常少数的网站依然在用浮动来布局

与传统布局的对比

  • 传统布局

    • 兼容性好
    • 布局繁琐
    • 局限性,不能在移动端很好的布局
  • flex 弹性布局

    • 操作方便,布局极为简单,移动端应用很广泛
    • PC 端浏览器支持情况较差
    • IE 11 或更低版本,不支持或仅部分支持
  • 建议:

    • 如果是 PC 端页面布局,我们还是传统布局。
    • 如果是移动端或者不考虑兼容性问题的 PC 端页面布局,我们还是使用 flex 弹性布局

flex 布局初体验

1656553355551

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
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
/* 01 给 div 只需要添加 “display:flex” 即可 */
div {
display: flex;
width: 600px;
height: 200px;
background-color: #fac090;
}
/* 02 span 直接给宽度和高度,背景颜色,还有蓝色边框*/
span {
width: 150px;
height: 100px;
background-color: #95b3d7;
border: 1px solid #116ddd;
}
</style>
</head>

<body>
<div><span></span><span></span><span></span></div>
</body>

flex 布局原理

  • flex 是 flexible Box 的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性,任何一个容器都可以指定为 flex 布局。

  • 当我们为父盒子设为 flex 布局以后,子元素的 float、clear 和 vertical-align 属性将失效。

  • 伸缩布局 = 弹性布局 = 伸缩盒布局 = 弹性盒布局 = flex 布局

  • 采用 Flex 布局的元素,称为 Flex 伸缩容器(flex container),简称”容器”。它的所有子元素自动成为容器成员,称为 Flex 伸缩项(flex item),简称”项目”。

    • 体验中 div 就是 flex 父容器。
    • 体验中 span 就是 子容器 ,也叫 flex 项目
    • 子容器可以横向排列也可以纵向排列
  • 总结 flex 布局原理:

    • 就是通过给父盒子添加 flex 属性,来控制子盒子的位置和排列方式

1656553831510

flex 布局父元素常见属性

  • 以下由 6 个属性是对父元素设置的

    • flex-direction:设置主轴的方向

    • justify-content:设置主轴上的子元素排列方式

    • flex-wrap:设置子元素是否换行

    • align-content:设置侧轴上的子元素的排列方式(多行)

    • align-items:设置侧轴上的子元素排列方式(单行)

    • flex-flow:复合属性,相当于同时设置了 flex-direction 和 flex-wrap

flex-direction 主轴方向

  • 01 主轴与侧轴
    • 在 flex 布局中,是分为主轴和侧轴两个方向,同样的叫法有 : 行和列、x 轴和 y 轴
      • 默认主轴方向就是 x 轴方向,水平向右
      • 默认侧轴方向就是 y 轴方向,水平向下

1656554108426

  • 02 属性值
    • flex-direction 属性决定主轴的方向(即项目的排列方向)
    • 注意: 主轴和侧轴是会变化的,就看 flex-direction 设置谁为主轴,剩下的就是侧轴。而我们的子元素是跟着主轴来排列的

1656554168421

  • 在伸缩布局中,默认情况下水平方向是主轴,默认情况下主轴的起点在伸缩容器的最左边,默认情况下所有的伸缩项都是从主轴的起点开始排版的, 但是我们也可以通过属性来修改主轴的起点的位置
    • flex-direction: 用于修改主轴起点的位置
    • row: 起点在伸缩容器的最左边,终点在伸缩容器的最右边.从左至右的排版,默认的取值
    • row-reverse: 起点在伸缩容器的最右边,终点在伸缩容器的最左边,从右至左的排版
    • column: 起点在伸缩容器的最顶部,终点在伸缩容器的最底部,从上至下的排版
      • 注意点:在伸缩布局中主轴和侧轴永远都是十字交叉的,只要主轴的方向发生了变化,侧轴也会发生变化
    • column-reverse: 起点在伸缩容器的最底部,终点在伸缩容器的最顶部,从下至上的排版
1
2
3
4
flex-direction: row; /* 伸缩项从左到右排列 默认项 */
flex-direction: row-reverse; /* 伸缩项从右到左排列 */
flex-direction: column; /* 设置主轴为 y 轴,伸缩项从上到下排列 */
flex-direction: column-reverse; /* 设置主轴为 y 轴,伸缩项从下到上排列 */

justify-content 主轴元素排列

  • justify-content 属性定义了项目在主轴上的对齐方式
  • 注意: 使用这个属性之前一定要确定好主轴是哪个

1656554254171

1
2
3
4
5
6
flex-direction: row; /* 主轴为 x 轴*/
justify-content: flex-start; /* 伸缩项从左到右排列 类似于左对齐*/
justify-content: flex-end; /* 伸缩项从右到左排列 类似于右对齐*/
justify-content: center; /* 居中对齐 */
justify-content: space-between; /* 两端贴边,再平分剩余空间 类似于两端对齐 */
justify-content: space-around; /* 平分剩余空间 */

flex-wrap 子元素换行

  • 默认情况下,项目都排在一条线(又称”轴线”)上。flex-wrap 属性定义,flex 布局中默认是不换行的。

1656554319839

1
2
3
4
5
6
7
8
9
10
/*
1.默认情况下如果伸缩容器的一行放不下所有的伸缩项,那么系统会自动等比压缩所有的伸缩项
2.在伸缩容器中有一个叫做 flex-wrap 属性,专门用于控制放不下是否需要换行的
默认的取值:
flex-wrap : 不换行
wrap : 放不下就换行而不是等比压缩
wrap-reverse : 放不下就换行,以行为单位进行反转*/
flex-wrap: nowrap;
flex-wrap: wrap;
flex-wrap: wrap-reverse;

align-items 侧轴元素排列(单行)

  • 该属性是控制子项在侧轴(默认是 y 轴)上的排列方式 在子项为单项(单行)的时候使用

1656554369596

1
2
3
4
5
6
7
8
9
10
11
12
13
/* 告诉浏览器排版好的伸缩项需要和侧轴的起点对齐*/
align-items: flex-start;
align-items: flex-end;
align-items: center;

/* baseline:让所有伸缩项中的基线在一条直线上对齐*/
align-items: baseline;

/* stretch (拉伸对齐/等高对齐):
让所有的伸缩项的高度变为侧轴的高度
注意点:
如果需要设置为拉伸对齐,那么伸缩项不能设置高度,如果伸缩项设置了高度,那么拉伸对齐就会失效 */
align-items: stretch;

align-content 侧轴元素排列(多行)

  • 设置子项在侧轴上的排列方式,并且只能用于子项出现 换行 的情况(多行),在单行下是没有效果的。

1656554491124

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
在伸缩容器中有一个叫做 align-content 的属性,是专门用于设置换行之后的对齐方式的
注意点:只有伸缩项发生了换行这个属性才有效
flex-start: 换行之后和侧轴的起点对齐,一行接一行
flex-end: 换行之后和侧轴的终点对齐,将所有换行之后的内容当做一个整体来操作
center: 换行之后和侧轴的中点对齐
space-between: 换行之后在侧轴上两端对齐
space-around: 换行之后在侧轴上环绕对齐
stretch: 以行为单位进行拉伸,拉伸的部分以空白填充,保证拉伸之后所有的行加起来能够填满侧轴
*/
align-content: flex-start;
align-content: flex-end;
align-content: center;
align-content: space-between;
align-content: space-around;
align-content: stretch;

align-content 和 align-items 区别

  • align-items 适用于单行情况下, 只有上对齐、下对齐、居中和 拉伸
  • align-content 适应于换行(多行)的情况下(单行情况下无效), 可以设置 上对齐、 下对齐、居中、拉伸以及平均分配剩余空间等属性值。
  • 总结: 就是单行找 align-items 多行找 align-content

1656554620130

flex-flow 复合属性

  • flex-flow 属性是 flex-direction 和 flex-wrap 属性的复合属性
1
flex-flow: row wrap;
  • flex-direction:设置主轴的方向
  • flex-wrap:设置子元素是否换行
  • flex-flow:复合属性,相当于同时设置了 flex-direction 和 flex-wrap

flex 布局子项常见属性

  • flex 子项目占的份数
  • align-self 控制子项自己在侧轴的排列方式
  • order 属性定义子项的排列顺序(前后顺序)

flex 属性

  • flex 属性定义子项目分配剩余空间,用 flex 来表示占多少份数。
1
2
3
.item {
flex: <number>; /* default 0 */
}

align-self 子项在侧轴的排列

  • align-self 属性允许单个项目有与其他项目不一样的对齐方式,可覆盖 align-items 属性。
  • 默认值为 auto,表示继承父元素的 align-items 属性,如果没有父元素,则等同于 stretch。
1
2
3
4
span:nth-child(2) {
/* 设置自己在侧轴上的排列方式 */
align-self: flex-end;
}
1
2
3
4
5
6
7
/* 如果在伸缩容器中通过 align-items:来控制伸缩项的对齐方式,是一次性控制所有伸缩项的对齐方式,如果想单独的控制某一个伸缩项在侧轴上的对齐方式,那么需要将控制对齐方式的属性写到伸缩项中 */
/* align-items:写到伸缩容器中, 控制所有伸缩项 */
/* align-self:写到伸缩项中, 控制编写对应代码的那个伸缩项 */
/* align-self:的取值和 align-items 的取值是一样的,只是控制的范围和书写的位置不同而已 */
align-self: flex-start;
align-self: flex-end;
align-self: center;

order 定义项目的排列顺序

  • 数值越小,排列越靠前,默认为 0。属于伸缩项的属性
  • 注意:和 z-index 不一样。
1
2
3
4
5
6
7
8
/*
默认情况下每一个伸缩项都有一个 order 属性,用于决定排序的先后顺序默认情况下所有伸缩项的 order 属性的取值都是 0
我们可以通过修改 order 属性的取值来实现伸缩项的排序
排序的规则:从小到大的排序,越小的显示在越前面,越大的显示在越后面
*/
.item {
order: 999;
}

flex-grow 扩充属性

  • 在伸缩项中有一个 flex-grow 属性,用于控制当所有伸缩项的宽度总和小于伸缩容器宽度的时候如何扩充自己,以便于所有伸缩项宽度的总和能够填满整个伸缩容器

  • 默认情况下 flex-grow 的取值是 0,表示我们设置的宽度是多少就按照多少来显示,不进行任何的扩充

  • 注意点:

    • 只有当所有伸缩项的宽度总和小于伸缩容器宽度的时候, flex-grow 这个属性才有效
  • flex-grow 扩充的公式

    • 1 利用伸缩容器宽度 – 所有伸缩项的总宽度 = 剩余空间
      • 600 - 300 = 300
    • 2 利用剩余空间 / 所有需要扩充份数的总和 = 每一份的大小
      • 300 / (1 + 4 + 8)= 23.07
    • 3 利用当前伸缩项的宽度+需要的份数的宽度
      • 第一个伸缩项 =100 + (1 * 23.07) = 123.07
      • 第二个伸缩项 =100 + (4 * 23.07) = 192.28
      • 第三个伸缩项 =100 + (8* 23.07) = 284.56
1
2
3
4
5
flex-grow: 1;

flex-grow: 4;

flex-grow: 8;

flex-shrink 缩小属性

  • 在伸缩项中有一个 flex-shrink 属性,用于控制当所有伸缩项的宽度总和大于伸缩容器宽度的时候如何缩小自己,以便于所有伸缩项宽度的总和能够填满整个伸缩容器

  • 默认情况下 flex-shrink 的取值是 1,表示当所有伸缩项宽度的总和大于伸缩容器宽度的时候等比缩小自己

  • 注意点:

    • 只有当所有伸缩项的宽度总和大于伸缩容器宽度的时候, lex-shrink 这个属性才有效
  • flex-shrink 扩充的公式

    • 1 利用所有伸缩项的宽度总和 – 伸缩容器宽度 = 溢出的宽度
      • 900- 600 = 300
    • 2 计算权重值
      • 利用每一个伸缩项需要的份数 * 当前伸缩项的宽度然后再相加, 1 * 300 + 4 _ 300 + 8_ 300 = 3900
    • 3 计算每个伸缩项需要缩小的范围
      • 溢出的宽度 * 当前伸缩项的宽度 * 当前伸缩项需要的份数 / 权重值 300 * 300 *1/3900 = 23.07
      • 第一个伸缩项宽度 = 300 - 23.07 = 276.9 300 _ 300_ 4/3900 = 92.3
      • 第二个伸缩项宽度 = 300 - 92.3 = 207.6
1
2
3
4
5
flex-shrink: 1;

flex-shrink: 4;

flex-shrink: 8; /* 值越大,缩小越狠 */
  • 注意点:
    • 1 如果没有指定 flex-grow 属性,或者 flex-grow 的值是 0,那么当前的伸缩项不会被扩充
    • 2 如果 flex-shrink 的值是 0,那么当前的伸缩项不会被缩小
    • 3 注意点
      • 前面所写的注释都是说宽度扩充或者宽度缩小,但是这种说法是不严谨的也有可能扩充和缩小的是高度,到底是宽度还是高度是由主轴决定的, 扩充和缩小的是主轴方向上的值
      • 也就是说如果主轴是水平方向的,那么扩充和缩小的就是宽度, 也就是说如果主轴是垂直方向的,那么扩充和缩小的就是高度

flex-basis 设置宽度

  • 1 在伸缩布局中可以通过 flex-basis 属性设置伸缩项的宽度
    • 注意点: flex-basis 只有在伸缩布局中才有效
  • 2 在伸缩布局中如果通过 flex-basis 设置了宽度,那么再通过 width 设置宽度就会无效, 也就是说 flex-basis 的优先级要高于 width 的优先级
  • 3 在伸缩布局中如果同时通过 flex-basis 和 width 设置了宽度,而且一个设置的是 auto,一个设置的是具体的值,那么会按照具体的值来显示
1
2
3
4
5
6
7
8
flex-basis: 100px; /*同时设置 width 和 flex-basis,会以 flex-basis 为准*/
width: 200px;

width: 200px; /* 同时设置 width 和 flex-basis,会以 具体值的 为准 */
flex-basis: auto;

flex-basis: 300px; /* 同时设置 width 和 flex-basis ,会以 具体值的 为准 */
width: auto;

伸缩项属性连写

1
2
3
/* flex:扩充缩小宽度; */
/* 默认值: flex:0 1 auto; */
flex: 0 1 200px;

携程网案例

  • 技术选型

    • 方案:我们采取单独制作移动页面方案
    • 技术:布局采取 flex 布局
  • 设置视口标签以及引入初始化样式

1
2
3
4
5
6
7
<meta
name="viewport"
content="width=device-width, user-scalable=no,
initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<link rel="stylesheet" href="css/normalize.css" />
<link rel="stylesheet" href="css/index.css" />
  • 常用初始化样式
1
2
3
4
5
6
7
8
9
10
11
body {
max-width: 540px;
min-width: 320px;
margin: 0 auto;
font: normal 14px/1.5 Tahoma, 'Lucida Grande', Verdana, 'Microsoft
Yahei', STXihei, hei;
color: #000;
background: #f2f2f2;
overflow-x: hidden;
-webkit-tap-highlight-color: transparent;
}
  • 常见模块命名

1656555457323

1656555469979

  • 常见 flex 布局思路

1656555519273

  • 背景线性渐变

1656555584915

1
2
3
/* background: linear-gradient(起始方向, 颜色1, 颜色2, ...); */
background: -webkit-linear-gradient(left, red, blue);
background: -webkit-linear-gradient(left top, red, blue);
  • 背景渐变必须添加浏览器私有前缀
  • 起始方向可以是: 方位名词 或者 度数 , 如果省略默认就是 top