- A+
1. Flex布局与响应式布局
1.1 为什么需要响应式布局?
在电脑PC端,使用浮动,定位同时使用像素px单位就可以完成大部分布局,而且布局完之后不会有大问题,但是到了移动端,移动设备的屏幕尺寸多种多样,从小屏幕的智能手机到大屏幕的平板电脑,甚至是可穿戴设备,简单地运用和PC端一样的方式就会出现一些布局和排列的问题。
这里用PC端的缩放浏览器来举个例子,当浏览器缩小的时候,百度就只显示了一部分,无法在缩小的屏幕(浏览器窗口)中完全显示。
移动前端中常说的 viewport (视口)就是浏览器中用于呈现网页的区域。视口通常并不等于屏幕大小,特别是可以缩放浏览器窗口的情况下,为了确保在不同设备上都能够提供良好的用户体验,需要使用响应式布局来适应不同的屏幕尺寸。
1.2 响应式布局的解决方案
响应式布局有多种方案,比如:
- 媒体查询:它允许根据设备的特性(如屏幕宽度、设备类型等)应用不同的样式规则。通过使用媒体查询,可以针对不同的屏幕尺寸和设备类型应用不同的样式,从而实现响应式布局。
- 流式布局(百分比布局):它是一种基于相对单位(如百分比)进行设计的布局方式。在流式布局中,元素的宽度和高度相对于父元素或视口进行计算,使得它们可以根据可用空间的大小进行自适应调整。流式布局可以使页面在不同屏幕尺寸下保持比例和流动性。
- Flex布局:Flexbox是CSS3中的一种弹性盒子布局模型,它提供了强大的排列和对齐功能,可以实现灵活的响应式布局。通过使用Flexbox属性和值,可以轻松地控制元素在容器中的位置、顺序和大小。
- 栅格系统:栅格系统是一种将页面划分为多个网格列的布局方式,通过定义网格列数和间距来布局页面内容。栅格系统通常与媒体查询和流式布局结合使用,以实现在不同屏幕尺寸下的响应式布局。流行的栅格系统包括Bootstrap的栅格系统和Foundation的栅格系统。
本文主要介绍Flex布局
1.3 Flex布局的优越性
排列灵活,样式简单:Flex布局在响应式解决方案中具有灵活的排列和对齐、自适应的弹性性质、自动换行和调整顺序以及容器和项目的灵活性等优点,可以通过简单的CSS属性设置来控制元素在容器中的位置和布局。通过设置容器的flex-direction、justify-content和align-items等属性,可以轻松实现水平或垂直方向上的排列和对齐需求。这种灵活性使得在不同设备上适应不同布局要求变得容易。相比起针对不同屏幕来设置的媒体查询,相同的样式设置就可以适配多种屏幕尺寸,Flex布局非常的方便。
自动换行,调整顺序:在移动设备上,屏幕空间有限,需要在有限的空间中合理布局元素。Flex布局可以通过设置flex-wrap属性实现自动换行,使得项目可以在一行排列不下时自动换行到下一行。此外,还可以使用order属性调整项目的显示顺序,以便在移动设备上优先显示重要内容。这种自动换行和调整顺序的特性使得在小屏幕设备上实现良好的用户体验变得简单。
除了响应式布局外,在PC端也可以利用Flex布局来替代浮动和定位,完成很好的元素排列,让开发者免去使用float,position来布局的不便。最常见的八股文面试题,垂直水平居中就可以用flex布局轻松完成,这也是工作中较为常用的方式。
2. Flex布局定义
Flex布局对于元素的内联(行内)或块级的性质是不关心的。在Flex布局中,元素会根据容器和项目的属性进行排列,无论元素是行内元素还是块级元素。采用Flex布局的元素,称为Flex容器(flex container),简称”容器”。Flex容器的所有子元素自动成为容器成员,称为Flex项目(flex item),简称”项目”。
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。
项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。
3. Flex容器属性
3.1 开启flex布局display:flex
元素写了这个属性之后,就变成了一个flex的容器,就可以通过flex布局相关的方式去操作排列子元素。
<style> .parent{ display: flex; width: 400px; height: 200px; background-color:blueviolet; } .child{ width: 100px; height: 50px; background-color: aqua; border: 1px solid black; } </style> </head> <body> <div class="parent"> <div class="child">1</div> <div class="child">2</div> </div> </body>
开启flex布局之后,没有进行其他的设置,可以看到这个排列和没有开启flex布局的时候是不一样的,2个块级元素,并没有上下排列,而是已经排列在左右。开启flex布局后,容器中的项目默认会沿着主轴进行排列,此时没有对容器和项目进行其他的设置,主轴也按照默认的方向水平放置,所以2个子盒子都沿着主轴水平排列了。
3.2 改变主轴的方向flex-direction属性
flex-direction属性决定了主轴的方向,所有容器中的项目都会根据主轴方向来排列。
flex-direction 属性有四个可能的取值:
- row(默认值):Flex 项目水平排列,起点在左端,终点在右端。主轴从左到右。
- row-reverse:Flex 项目水平排列,起点在右端,终点在左端。主轴从右到左。
- column:Flex 项目垂直排列,起点在顶部,终点在底部。主轴从上到下。
- column-reverse:Flex 项目垂直排列,起点在底部,终点在顶部。主轴从下到上。
图中显示flex-direction的值为row时元素按顺序从左往右横向排列,子元素贴着父元素的左侧
1 .parent{ 2 display: flex; 3 flex-direction: row; 4 width: 400px; 5 height: 200px; 6 background-color:blueviolet; 7 }
图中显示flex-direction的值为row-reverse时元素按顺序从右往左横向排列,子元素贴着父元素的右侧(代码同上)
图中显示flex-direction的值为column时元素按顺序从上往下竖向排列,子元素贴着父元素的顶部,这一点类似于常规的文档流中块级元素的排列(代码同上)
图中显示flex-direction的值为column-reverse时元素按顺序从下往上竖向排列,子元素贴着父元素的底部(代码同上)
总的来说,flex-direction属性虽然简单,但是有重要的作用,可以
- 控制主轴方向:flex-direction 属性决定了主轴的方向,即 Flex 项目在水平方向或垂直方向上的排列。通过设置不同的取值,我们可以实现水平排列(左到右或右到左)或垂直排列(从上到下或从下到上)的布局。
- 确定起点和终点:flex-direction 属性的取值影响了 Flex 项目在主轴上的起点和终点的位置。在 row 值下,起点位于左端,终点位于右端;在 row-reverse 值下,起点位于右端,终点位于左端;在 column 值下,起点位于顶部,终点位于底部;在 column-reverse 值下,起点位于底部,终点位于顶部。这种控制起点和终点的能力对于设计布局非常有用。
- 影响项目排列顺序:flex-direction 属性还决定了 Flex 项目在主轴上的排列顺序。在默认的 row 值下,Flex 项目按照其在 HTML 结构中的顺序从左到右排列;在 row-reverse 值下,项目按照相反的顺序从右到左排列;在 column 值下,项目按照结构顺序从上到下排列;在 column-reverse 值下,项目按照相反的顺序从下到上排列。通过改变项目的排列顺序,我们可以调整 Flex 布局的外观和行为。
3.3 改变换行方式flex-wrap属性
flex-wrap属性决定了换行相关的策略。它决定了当弹性容器的宽度不足以容纳所有子元素时,是否允许子元素换行并如何排列。
它有几个常用的属性值:
- nowrap(默认值):子元素不换行,尽可能地将它们放在一行内,即使溢出弹性容器的边界。
- wrap:如果子元素在一行内放不下,将它们进行换行,从新行开始排列。
- wrap-reverse:与 wrap 相同,但换行时的排列顺序与正常顺序相反。
当没有写flex-wrap属性时,所有元素会默认沿着主轴在一行(或一列)排列。这也就和写了flex-wrap: nowrap是等效的
在已经给子项目设置了100px的宽度的情况下,6个项目仍然会排在同一行,而此时父元素的宽度也只有400px,说明此时子项目的宽度已经被压缩了变成了小于100px。
1 <style> 2 .parent { 3 display: flex; 4 width: 400px; 5 height: 200px; 6 background-color: blueviolet; 7 } 8 9 .child { 10 width: 100px; 11 height: 50px; 12 background-color: aqua; 13 border: 1px solid black; 14 } 15 </style> 16 <body> 17 <div class="parent"> 18 <div class="child">1</div> 19 <div class="child">2</div> 20 <div class="child">3</div> 21 <div class="child">4</div> 22 <div class="child">5</div> 23 <div class="child">6</div> 24 </div> 25 </body>
当希望子项目完成换行的时候可以设置flex-wrap: wrap
明显可以看到,图片已经完成了换行效果,但是这里上下两行元素出现了空隙,似乎与预期效果不符合,这是由于多行对齐时的align-content的默认值导致的,具体align-content用法会在后文解释。
1 .parent { 2 display: flex; 3 flex-wrap: wrap; 4 width: 400px; 5 height: 200px; 6 background-color: blueviolet; 7 } 8 9 .child { 10 width: 100px; 11 height: 50px; 12 background-color: aqua; 13 border: 1px solid black; 14 }
3.4 主轴对齐方式justify-content属性
justify-content是flex布局中的重要属性之一,用于定义和调整弹性容器中项目在主轴上的对齐方式。它控制项目沿着主轴的分布方式,包括项目之间的间距、对齐和对齐方式的调整。
这个属性常用的有以下几个值
- flex-start(默认值):将项目对齐到弹性容器的起始位置。项目靠主轴起始端对齐。
- flex-end:将项目对齐到弹性容器的末尾位置。项目靠主轴末尾端对齐。
- center:将项目在主轴上居中对齐。项目在主轴上平均分布,两端留有相同的空白。
- space-between:将项目在主轴上平均分布,并使项目之间的间距相等。首个项目对齐到主轴起始端,最后一个项目对齐到主轴末尾端。
- space-around:将项目在主轴上平均分布,并使项目之间的间距相等。首尾两端的间距是相邻项目间距的一半。
- space-evenly:将项目在主轴上平均分布,并使项目之间的间距相等。首尾两端和相邻项目之间的间距相等。
不写justify-content或者justify-content的值为flex-start时,flex容器内部的项目会按顺序沿着主轴排列,也就是当主轴是水平的时候就横过来排列,主轴是竖直的就竖过来排列。
以较常见的flex-direction取默认值row的时候举例,有类似于float:left的效果,但是不会出现子元素浮动后脱离文档流导致父元素高度塌陷的问题。
1 .parent { 2 display: flex; 3 justify-content: flex-start; 4 width: 400px; 5 height: 200px; 6 background-color: blueviolet; 7 }
justify-content的值为flex-end时,子元素也就是flex容器会靠主轴的终点处对齐,与前面的flex-start呈现相反的对齐排列效果。
以较常见的flex-direction取默认值row的时候举例,类似于float:right的效果,但是与右浮动不同的是右浮动会导致元素倒序排列而flex-end会保持元素的顺序,元素的排列顺序仍然是1,2,3。
1 <div class="parent"> 2 <div class="child">1</div> 3 <div class="child">2</div> 4 <div class="child">3</div> 5 </div>
对于右浮动会出现倒序的原因,这里进行简单的解释:
浮动的元素直到碰到边缘或另一个浮动元素的边缘为止,而代码又是从上往下执行,对于第一个child会优先进行浮动,碰到父盒子右边缘,结束,第二个child再开始浮动,碰到第一个child的左边缘再结束,第三个child在第二个child浮动结束后再浮动,就贴着第二个child左边缘。
解决右浮动倒序的方法可以有以下几种:
- 利用flex布局的flex-end,如上图所示
- 倒序书写元素,这样就可以正序排列了。
- 对于多个右浮动的child,再在外面加一层div包裹,先让外层的div右浮动(只有一个盒子,不会出现顺序问题的同时又能靠右对齐),然后让每个child左浮动(左浮动不会导致顺序出现问题,又可以实现浮动效果),代码和图片如下
<style> .parent { width: 400px; height: 200px; background-color: blueviolet; } .wrapper { float: right; } .child { float: left; width: 100px; height: 50px; background-color: aqua; border: 1px solid black; } </style> </head> <body> <div class="parent"> <div class="wrapper"> <div class="child">1</div> <div class="child">2</div> <div class="child">3</div> </div> </div> </body>
justify-content的值为center时,flex容器内的元素在主轴上居中对齐,向两边平均分布
以较常见的flex-direction取默认值row的时候举例,图中利用flex布局的justify-content:center 可以非常方便地实现块级元素的居中对齐
justify-content的值为space-between时,项目会在主轴两端对齐,中间平均排列,让不同的项目之间的间距相等
这里将每个child的宽度调成50px让多个盒子都能呈现在父容器内(同时避免尺寸发生变化)以展示space-between的效果。
这种布局形式在真实开发中也较为常用,有许多场景都需要两端对齐后,中间均分空隙。
以较常见的flex-direction取默认值row的时候举例,可以看到子项目中的间距都是相同的。在没有设置任何margin的情况下,元素也可以完成分离。
1 .parent { 2 display: flex; 3 justify-content: space-between; 4 width: 400px; 5 height: 200px; 6 background-color: blueviolet; 7 } 8 9 .child { 10 width: 50px; 11 height: 50px; 12 background-color: aqua; 13 border: 1px solid black; 14 }
justify-content的值为space-around时,每个项目自身的左右间距会相等,类似于设置了左右两边相同的margin值
以较常见的flex-direction取默认值row的时候举例,看起来首尾元素间距更窄,是因为对于中间元素一共有2份间距,前一个元素的右间距+后一个元素的左间距,所以中间的间距是首尾的两倍。
justify-content的值为space-evenly时,所有项目的间距都会相等,前面提到的space-around会让每个项目自身都具有相同左右边距,导致中间的间距叠加成立首尾的2倍。而space-evenly中会让所有的间距都相等,包括刚才所提到的首尾和中间。
以较常见的flex-direction取默认值row的时候举例,所有间距都相同。
3.5 交叉轴单行对齐align-items属性
与justify-content对应的,align-items用于定义和调整弹性容器中项目在交叉轴上的对齐方式,它同样也控制项目沿着交叉轴的分布方式,包括项目之间的间距、对齐和对齐方式的调整。
这个属性有以下几个常用的值
- stretch(默认值):将项目在交叉轴上拉伸以填充整个弹性容器。项目将沿交叉轴方向拉伸至与容器的交叉轴尺寸相等。
- flex-start:将项目对齐到弹性容器的交叉轴起始位置。项目靠交叉轴起始端对齐。
- flex-end:将项目对齐到弹性容器的交叉轴末尾位置。项目靠交叉轴末尾端对齐。
- center:将项目在交叉轴上居中对齐。项目在交叉轴上平均分布,上下留有相同的空白。
- baseline:将项目在交叉轴上与其基线对齐。项目的基线与其他项目的基线对齐。
这里先从默认不写这个属性来看,虽然align-items里也有和justify-content相同的flex-start值,但是这里的默认值并不是flex-start而是stretch,stretch的意思是伸展、延伸,也就是说写了stretch之后(或者直接不写align-items让他取默认值),项目会在交叉轴上伸展。
以没有写高度的项目举例
1 .parent { 2 display: flex; 3 justify-content: stretch; 4 width: 400px; 5 height: 200px; 6 background-color: blueviolet; 7 } 8 9 .child { 10 width: 50px; 11 background-color: aqua; 12 border: 1px solid black; 13 }
注意,以上代码中,子元素没有设置高度,所以flex项目完成拉伸并且在交叉轴上填满整个父容器的高度(或宽度),当然如果项目分多行排列,也会撑满整个父容器,每个项目的高度会被拉伸到:父元素高度/行数。
如果子项目已经设置了高度,那么这个属性就不会生效,不会再去拉伸项目。同样的如果主轴是垂直的,项目没有写宽度,也会横向撑满整个容器
1 .parent { 2 display: flex; 3 align-items: stretch; 4 width: 400px; 5 height: 200px; 6 background-color: blueviolet; 7 } 8 9 .child { 10 width: 50px; 11 height: 50px; 12 background-color: aqua; 13 border: 1px solid black; 14 }
align-items为flex-start时,子项目都沿着交叉轴靠着交叉轴的起点对齐
这里因为只有一行(没有设置换行属性,也没有一行排列不下),整个容器的上端也就是交叉轴的起点, 所以看起来和上面的图没什么区别。
align-items为flex-end时,子项目都沿着交叉轴靠着交叉轴的终点对齐
和上图相反的是,设置了这个属性,一行的项目就来到了容器底部,因为默认情况下交叉轴从上往下,容器的底部也就是整个交叉轴的终点
align-items为center时,子项目都沿着交叉轴靠着交叉轴居中对齐,往两边平均分布
设置了center后,子项目来到居中的位置。这也是在flex布局中最常用的居中技巧之一。如果需要垂直方向的居中,可以直接使用flex布局并且写上align-items: center。
align-items为baseline时,项目会按照文本的基线对齐
先针对第二个项目设置了一个padding,这样第二个项目的文字就会被挤下去,所以文字就不会在同一条基线上了
1 <style> 2 .parent { 3 display: flex; 4 width: 400px; 5 height: 200px; 6 background-color: blueviolet; 7 } 8 9 .child { 10 width: 50px; 11 height: 50px; 12 background-color: aqua; 13 border: 1px solid black; 14 } 15 16 #two { 17 padding-top: 10px; 18 } 19 </style> 20 <body> 21 <div class="parent"> 22 <div class="child">1</div> 23 <div class="child" id="two">2</div> 24 <div class="child">3</div> 25 <div class="child">4</div> 26 <div class="child">5</div> 27 <div class="child">6</div> 28 </div> 29 </body>
如果设置align-items: baseline之后,项目明显都在同一条基线上。
3.6 交叉轴多行对齐align-content属性
在上文的flex-wrap中,换行显示的盒子出现了一些空隙,这就和align-content有关系,align-content是CSS中用于控制flex容器中多行项目的对齐方式的属性。它适用于具有多行内容的flex容器,并决定了这些行在容器中的项目在交叉轴上的对齐方式。
以下是align-content的一些常用的取值:
- flex-start:将多行项目对齐到容器的起始位置。第一行将与容器的顶部对齐。
- flex-end:将多行项目对齐到容器的结束位置。最后一行将与容器的底部对齐。
- center:将多行项目在容器中垂直居中对齐。
- space-between:在容器中平均分布多行项目,使第一行在容器的顶部,最后一行在容器的底部,剩余的行平均分布在中间。
- space-around:在容器中平均分布多行项目,使每行周围具有相等的空间,包括顶部和底部。
- space-evenly:在容器中平均分布多行项目,使每行之间和周围都具有相等的空间。
- stretch(默认值):在容器中平均分布多行项目,项目将被拉伸以填充整个容器的高度。
需要注意的是,align-content只在有多行的情况下才会生效,而在只有一行的情况下是不会产生任何效果的,所以以下的示例全部会涉及到flex-wrap换行。
当默认不写align-content时,align-content的值默认取stretch,也就是会把每一个项目都会拉伸来撑满整个容器,这里最多2行,所以每个项目的高度都被拉伸到了容器高度/2。
当对子项目设置高度的时候,项目不会被拉伸,但是原来拉伸后的空间会有间距填充
1 .parent{ 2 display: flex; 3 flex-wrap: wrap; 4 /* 默认值,也可以不写 */ 5 align-content: stretch; 6 width: 400px; 7 height: 200px; 8 background-color:blueviolet; 9 } 10 .child{ 11 width: 100px; 12 background-color: aqua; 13 border: 1px solid black; 14 }
当align-content的值取flex-start时,第一行会靠着交叉轴起点,也就是顶部对齐,不会留有上图那样的间距
当align-content的值取flex-end时,最后一行会靠着交叉轴终点,也就是底部对齐,也不会留有上图那样的间距
当align-content的值取center时,项目会在交叉轴上居中对齐,向两边平均分布,这个与之前的align-items和justify-content相似
当align-content的值取space-between时,项目会在交叉轴上贴着两端,中间间距相同
当align-content的值取space-around时,每个项目的上下间距相同,和justify-content一样,因为中间的间距叠加,首尾的间距是中间间距的一半
当align-content的值取space-evenly时,所有交叉轴上的间距相同
4. Flex项目属性
4.1 改变项目的显示顺序order属性
order属性用于控制Flex容器中子元素的排序。默认情况下,Flex容器中的子元素按照它们在HTML源代码中的顺序进行排列,但是使用order属性,我们可以改变这个顺序
每个Flex项目的order属性默认值是0。你可以为项目设定任意整数值,数值可以是正数、0或者负数。具有较小order值的元素将被优先排列,具有相同order值的元素将按照它们在HTML源代码中的原始顺序排列。
1 .parent{ 2 display: flex; 3 flex-wrap: wrap; 4 align-content: flex-start; 5 width: 400px; 6 height: 200px; 7 background-color:blueviolet; 8 } 9 .child{ 10 width: 100px; 11 height: 50px; 12 background-color: aqua; 13 border: 1px solid black; 14 } 15 #two{ 16 order: -1; 17 } 18 #three{ 19 order: -2; 20 }
4.2 子项目扩张flex-grow属性
flex-grow用于设置或检索flex容器中的flex子项目的能力,以根据其在flex容器中的空间比例来伸展和占用空间。
flex-grow属性的默认值为0,表示子项目将不会伸展以填充容器。
flex可以取的值是所有非负数,数值不带单位,表示当容器有剩余空间的时候,子项目按比例去增大,占满容器。子项目扩张的算法如下:比如剩余空间为 x,三个元素的 flex-grow 分别为 a,b,c。设 sum 为 a + b + c。那么三个元素将得到剩余空间分别是 x * a / sum, x * b / sum, x * c / sum
对第三个子项目进行设置flex-grow:1,表示的意思是:有剩余空间的时候,第三个项目会扩张,占一份,因为只有一个元素设置了flex-grow,所以第三项目占满了所有剩余空间。
此时如果对第三个项目设置flex-grow:2/3/4/5....都不会使他变得更大,因为剩余空间只有那么多,其他的元素也都是flex-grow:0。
对多个项目设置flex-grow时,它们就按照比例来占满剩余空间,第二个子项目占1份(四分之一),第三个子项目占3份(四分之三)
1 .parent { 2 display: flex; 3 width: 400px; 4 height: 200px; 5 background-color: blueviolet; 6 } 7 8 .child { 9 width: 50px; 10 height: 50px; 11 background-color: aqua; 12 border: 1px solid black; 13 } 14 15 #two { 16 flex-grow: 1; 17 } 18 19 #three { 20 flex-grow: 3; 21 }
前面有说到,flex-grow可以设置所有非负的值,当所有的子项目flex-grow的值之和小于1时,计算扩张的算法会发生改变,不再只是将所有的剩余空间的按flex-grow的比例分配,而是将剩余空间*sum(三个元素的 flex-grow 分别为 a,b,c设 sum 为 a + b + c)按flex-grow的比例分配。也可以等效地理解为按上面讲的算法x * a / sum, x * b / sum, x * c / sum,当sum<1时,分母直接使用1。
如下图,第二个子项目获得剩余空间的20%,第三个子项目获得剩余空间的60%,剩下的20%仍然空出。
1 .parent { 2 display: flex; 3 width: 400px; 4 height: 200px; 5 background-color: blueviolet; 6 } 7 8 .child { 9 width: 50px; 10 height: 50px; 11 background-color: aqua; 12 border: 1px solid black; 13 } 14 15 #two { 16 flex-grow: 0.2; 17 } 18 19 #three { 20 flex-grow: 0.6; 21 }
简单案例:之前在开发中遇到一个需求,后端会给前端传许多一段一段的标签,每个标签的宽度都不一样长,这些标签要换行排列。每一行的标签要贴着左右边缘,中间间距相等(justify-content: space-between)。最后一行标签一般都会数量较少,如果仅仅使用justify-content: space-between而不对最后一行专门处理,最后一行的间距就会特别大,影响最后页面效果的呈现。
为了解决最后一行标签数量较少的问题,可以在容器末尾加一个看不见的盒子,让那个盒子占满剩余的空间,也就是利用flex-grow: 1
以下用简单的代码模拟了一下上述开发场景
1 <style> 2 .parent { 3 display: flex; 4 flex-wrap: wrap; 5 justify-content: space-between; 6 width: 400px; 7 height: 200px; 8 background-color: blueviolet; 9 } 10 11 .child { 12 width: 100px; 13 height: 40px; 14 background-color: aqua; 15 border: 1px solid black; 16 font-size: 18px; 17 } 18 19 .hidden { 20 flex-grow: 1; 21 visibility: hidden; 22 } 23 </style> 24 <body> 25 <div class="parent"> 26 <div class="child">1</div> 27 <div class="child" style="width: 120px;">2</div> 28 <div class="child" style="width: 30px;">3</div> 29 <div class="child">4</div> 30 <div class="child" style="width: 150px;">5</div> 31 <div class="child">6</div> 32 <div class="child">7</div> 33 <div class="child">8</div> 34 <div class="child">9</div> 35 <div class="hidden"></div> 36 </div> 37 </body>
4.3 子项目收缩flex-shrink属性
flex-shrink用于指定项目在容器中缩小的能力,当 flex 容器空间不足时候,单个元素的收缩比例。当父元素的宽度小于子元素宽度之和并且超出了父元素的宽度时,flex-shrink 就会按照一定的比例进行收缩:将子元素宽度之和与父元素宽度的差值按照子元素 flex-shrink 的值分配给各个子元素,每个子元素原本宽度减去按比例分配的值,其剩余值为实际宽度。
flex-shrink的默认值是1,也就是说,当子元素宽度的和超出父容器的时候,所有子项目都等比例的缩小
下图中所有子项目的flex-shrink都取1,但是子项目的宽度是有不同的,第二个子项目宽度为120px,第三个子项目宽度为150px,其他所有子项目的宽度都是100px,他们宽度的和是100*4+120+150 = 670px,但是父容器宽度只有400px,也就是说超出了270px。此时要等比例缩小,要计算每个盒子要缩小的宽度,算法是:子项目宽度/(每个子项目的宽度*对应shrink的值)之和 * 超出的宽度。对于宽度为100的子项目要缩小的宽度是 (100*1)/(100*4*1+120*1+150*1)*270 = 40.29px,对于第二个宽度为120px的子项目要缩小的宽度是(120*1)/(100*4*1+120*1+150*1)*270 = 48.36px,对于第三个宽度为150px的子项目要缩小的宽度是(150*1)/(100*4*1+120*1+150*1)*270 = 60.48px
所有盒子在收缩后,最后的宽度=原来宽度-要缩小的宽度
1 .parent { 2 display: flex; 3 width: 400px; 4 height: 200px; 5 background-color: blueviolet; 6 } 7 8 .child { 9 width: 100px; 10 height: 50px; 11 flex-shrink: 1; 12 background-color: aqua; 13 border: 1px solid black; 14 } 15 #two{ 16 width: 120px; 17 } 18 #three{ 19 width: 150px; 20 }
当flex-shrink为0的时候,该子项目不会收缩
以第三个150px的盒子举例,让它的flex-shrink为0,它就不会收缩,其他盒子按比例收缩,宽度为100px的项目flex-shrink为1,要缩小的宽度为 (100*1)/(100*4*1+120*1.5+150*0)*270 = 46.55px, 宽度为120px的项目flex-shrink为1.5,要缩小的宽度为 (120*1.5)/(100*4*1+120*1.5+150*0)*270 = 83.79px
1 .parent { 2 display: flex; 3 width: 400px; 4 height: 200px; 5 background-color: blueviolet; 6 } 7 8 .child { 9 width: 100px; 10 height: 50px; 11 flex-shrink: 1; 12 background-color: aqua; 13 border: 1px solid black; 14 } 15 #two{ 16 width: 120px; 17 flex-shrink: 1.5; 18 19 } 20 #three{ 21 width: 150px; 22 flex-shrink: 0; 23 24 }
4.4 子项目初始尺寸flex-basis属性
flex-basis用于设置flex容器中项目的初始大小。它定义了一个项目在主轴上的初始尺寸,即在项目没有被放大或缩小之前的大小。flex-basis可以接受多种单位值,如像素(px)、百分比(%)、视口宽度(vw)、视口高度(vh)等。
flex-basis常用的值有
- <length>:可以是像素值(px)、百分比(%)等,表示项目的初始尺寸。
- auto(默认值):项目的初始尺寸由其内容决定。如果项目没有设置尺寸或具有固定的尺寸,则自动计算尺寸。
- content:项目的初始尺寸由项目内容决定。
在Flex布局中,子项设置width是没有直接效果的,之前所有设置宽度并且生效是因为没有写flex-basis属性,也就是说flex-basis属性取了默认值auto,当flex-basis取auto的时候,容器的宽度就由子项自身的尺寸(比如width,max-width等)去渲染。
1 .parent { 2 display: flex; 3 width: 400px; 4 height: 200px; 5 background-color: blueviolet; 6 } 7 8 .child { 9 width: 50px; 10 height: 50px; 11 flex-basis: auto; 12 background-color: aqua; 13 border: 1px solid black; 14 }
在同时用长度设置flex-basis和width时,width将无效,根据flex-basis的值决定尺寸
在设置flex-basis为content时,子项目的尺寸根据内容的大小决定
4.5 联合写法flex属性
flex属性是flex-grow,flex-shrink,flex-basis三个属性的简写,用于控制子项目的缩放行为和初始尺寸。
flex的完整写法是 flex:<flex-grow> <flex-shrink> <flex-basis>,也就是一共有3个值要去设置,分别按顺序对应flex-grow,flex-shrink,flex-basis,而在日常工作中并不会经常写完整的写法,而较常用的是flex:1或者50%这种写法。
flex-grow和flex-shrink可以同时设置,但是对于一个元素,同时只会有其中一者生效,因为flex-grow需要有剩余空间才能进行拉伸分配而flex-shrink需要子元素宽度之和超过父元素(溢出)才会收缩,一个盒子要么空间不足,要么就空间超出,不可能既有剩余空间又宽度之和超出父元素
flex属性的常用值有
- flex: auto: 此值表示元素可以根据可用空间进行伸缩,可以扩展也可以收缩。
- flex: initial: 此值将 flex-grow、flex-shrink 和 flex-basis 设置为默认值。flex-grow 为 0,flex-shrink 为 1,flex-basis 为 auto。
- flex: none: 此值表示元素不应该伸缩。flex-grow 和 flex-shrink 均为 0,flex-basis 为其本来的大小。
- flex: 数字/百分比/长度
flex:auto代表的是 flex:1 1 auto(flex-grow:1, flex-shrink: 1, flex-basis: auto) ,表示的是根据具体空间来进行扩展或者收缩
flex:initial(默认值)代表的是 flex:0 1 auto(flex-grow:0, flex-shrink: 1, flex-basis: auto) ,表示子项目不会在有剩余空间时候扩张,但是超出时会要收缩。
flex:none 代表的是 flex:0 0 auto(flex-grow:0, flex-shrink: 0, flex-basis: auto),表示子项目不会扩张也不会收缩,保持原有尺寸
在超出父容器的时候,也会继续保持原有的尺寸
其他值:
如果只写一个值,类似于flex: 1 这种,分2种情况
- 如果写的是数字比如,flex: 1,flex: 2,flex: 3这种那设置的是flex-grow的值,其他2个值取默认
- 如果写的是百分比(flex: 20%)或者是长度(flex: 100px),就是设置的flex-basis属性,其他2个值取默认
如果只写两个值,第一个值对应的是flex-grow,第二个值对应2种情况
- 如果第二个值写的是数字比如,flex: 1,flex: 2,flex: 3这种那设置的是flex-shrink的值
- 如果写的是百分比(flex: 20%)或者是长度(flex: 100px),就是设置的flex-basis属性
如果写三个值,对应地去设置flex-grow、flex-shrink 和 flex-basis
简单案例:
场景1:简单实现一个两栏布局,左列定宽,右边自适应
这里用到flex: 1 让右边的项目自动根据剩余空间扩张
1 <style> 2 .parent { 3 display: flex; 4 width: 400px; 5 height: 200px; 6 background-color: blueviolet; 7 } 8 9 .child1 { 10 width: 100px; 11 height: 50px; 12 background-color: aqua; 13 border: 1px solid black; 14 } 15 .child2 { 16 height: 50px; 17 background-color: aqua; 18 flex: 1; 19 border: 1px solid black; 20 } 21 </style> 22 23 <body> 24 <div class="parent"> 25 <div class="child1">1111</div> 26 <div class="child2">2</div> 27 </div> 28 </body>
场景2:让多个盒子分行排列,每行要三个盒子,同时宽度自适应
这里要对父容器设置flex-wrap:wrap,对子项目设置,flex:33%来让它们每行排列3个
1 <style> 2 .parent { 3 display: flex; 4 justify-content: space-between; 5 flex-wrap: wrap; 6 width: 400px; 7 height: 200px; 8 background-color: blueviolet; 9 } 10 11 .child { 12 box-sizing: border-box; 13 flex: 33%; 14 height: 50px; 15 background-color: aqua; 16 border: 1px solid black; 17 } 18 </style> 19 20 <body> 21 <div class="parent"> 22 <div class="child">1</div> 23 <div class="child">2</div> 24 <div class="child">3</div> 25 <div class="child">4</div> 26 <div class="child">5</div> 27 <div class="child">6</div> 28 </div> 29 </body>
4.6 子项目单独对齐align-self属性
align-self属性用于调整Flex容器中单个项目(Flex项)的垂直对齐方式。它允许你为单个项目指定不同于其它项目的垂直对齐方式。align-self属性可以应用于任何Flex项,并覆盖容器级别的垂直对齐设置(通过align-items属性设置)
常用的值有:
- auto(默认值):继承自父容器的align-items属性。
- flex-start:项目与容器的顶部对齐。
- flex-end:项目与容器的底部对齐。
- center:项目在容器的垂直中心对齐。
- baseline:项目与容器的基线对齐。
- stretch:项目被拉伸以填充整个容器的高度。
这些取值都在前面的align-items中介绍过了,这里只用一些案例来演示align-self的效果
针对第二个子项目,设置了align-self: center,第三个子项目设置了align-self: flex-end
这里是单行的align-self效果
1 .parent { 2 display: flex; 3 align-items: flex-start; 4 width: 400px; 5 height: 200px; 6 background-color: blueviolet; 7 } 8 9 .child { 10 box-sizing: border-box; 11 width: 100px; 12 height: 50px; 13 background-color: aqua; 14 border: 1px solid black; 15 } 16 17 #two{ 18 align-self: center; 19 } 20 #three{ 21 align-self: flex-end; 22 }
如果在父容器中加入换行,效果如下