flex大法:一网打尽所有常见布局

算法星轨师
• 阅读 2010

flex全称Flexible Box模型,顾名思义就是灵活的盒子,不过一般都叫弹性盒子,所有PC端及手机端现代浏览器都支持,所以不用担心它的兼容性,有了这玩意,妈妈再也不用担心我们的布局。

先简单介绍一下,要使用flex布局,需要先给一个容器元素设置display:flex让它变成flex容器,然后其所有的直接子元素就变成flex子元素了,在flex里存在两根轴,叫主轴和交叉轴,互相垂直,主轴默认水平,flex子元素默认会沿主轴排列,可以控制flex子元素在主轴上伸缩,主轴方向可以设置,相关的css属性分为两类,一类是给flex容器设置的,一类是给flex子元素设置的,本文在介绍一些典型场景实现的同时也会顺带讲解部分属性,当然更详细的内容可以阅读MDN上的教程。

单列布局

单列布局是最简单的布局了,从上到下排列,如图:

flex大法:一网打尽所有常见布局

可以使用三个div来表示头、内容和尾,然后把外层容器,即body设为flex容器,因为flex默认的主轴是水平的,我们需要把它设置为垂直的,然后再设置元素在交叉轴居中即可:

flex大法:一网打尽所有常见布局

当然更常见的情况是内容高度不确定,这样我们往往会希望在内容高度不满一屏时底部内容挨着底边,超过一屏时跟在最后,这首先需要容器元素有固定的高度,否则何来底边,我们可以把htmlbody的高度都设为100%,然后去掉给content元素设置的高度,并给它添加一个带高度的子元素:

flex大法:一网打尽所有常见布局

接下来需要使用到flex-grow属性,这个是flex子元素上的属性,用来控制容器还有空间剩余时,flex子元素怎么进行扩展,默认值是0,也就是不扩展,子元素会显示为它们默认的大小,这个所谓的默认大小分几种情况:

1.如果子元素的另一个属性flex-basis设置了不为auto的具体数值,那么无论元素有没有设置具体大小都显示为该属性定义的尺寸;

2.如果子元素的flex-basis的值为auto(默认值),那么如果元素设置了具体的大小那么显示为该设置的尺寸;

3.否则取决于元素内容的max-content大小;

flex-grow设为一个正数时,那么各个子元素会按设置的份数来按比例分配剩余可用的空间,比如剩余空间为90px,三个子元素该属性值都设为1,那么每个元素将在原来大小的基础上加上90/3=30px

根据上述原理,我们只需要给content元素的flex-grow属性设为1即可,其他都是0,所以剩余空间将全给content元素:

flex大法:一网打尽所有常见布局

这样内容不足时底部就可以挨着底边了,但是当内容过多,超过一屏时:

flex大法:一网打尽所有常见布局

可以看到头和尾都没了,这是因为flex-shrink的原因,这个也是flex子元素上的属性,用来控制当子元素的尺寸之和已经超过容器了要怎么收缩元素,默认值为1,就是按比例减去要收缩的空间,理论上是这样,但实际上并没有这么简单,接下来简单测试一下:

容器元素body800px高,上中下高度分别为100+1000+100=1200px,根据1:1:1flex-shrink计算总权重为1*100+1*1000+1*100=1200,子元素总高度超过容器400px,这多出的要按的比例从各自高度中减去,具体为:

(400*1*100)/1200=33.33px
(400*1*1000)/1200=333.33px
(400*1*100)/1200=33.33px

,也就是分别都减去上述值,减完后理论上各自的高度变成了66.67px、666.67.67px、66.67px,但是实际上:

flex大法:一网打尽所有常见布局

可以看到头和尾都变成了0,内容高度没有变,这是为啥呢?上面我们提到了max-content,同样,这里对应着min-content的概念,虽然正常来说应该变成我们计算出的尺寸才对,但是减少到元素内容的min-content后它就不会再变小了,content元素有个高度为1000的子元素,这个高度就是它的min-content,所以它不会缩小,它一个元素就比容器元素高了,再加上头和尾因为都没有内容,所以虽然理论上它们不是为0的,但是为了更好的显示效果,浏览器就直接把它们减少到0了,我们可以随便给头和尾加一点文字,文字的高度就会变成它们的min-content,它们的高度也就不会变成0

flex大法:一网打尽所有常见布局

所以这就意味着不要想着去精确计算,把它交给浏览器,浏览器会给你以最好的方式呈现。

那么解决头和尾不要消失的问题很简单,可以给它们也加个固定高度的子元素,但是最简单的方法是把它们的flex-shrink设为0,也就是不收缩:

flex大法:一网打尽所有常见布局

这样就实现我们的需求了。

经典导航栏

flex大法:一网打尽所有常见布局

如图所示是一个经典的网站导航栏的布局,logo和导航在左,用户信息在右,不用flex可能会使用浮动,上图使用浮动还好,但是如果右边是两个块,那么右边浮动的元素的显示顺序和书写顺序要不一致才行,或者再用一个元素包裹一下,使用flex则没有这种烦恼。

该场景可以使用一个容器来包裹左边的logo和导航,再设置justify-content:space-between来实现,但是有个小技巧可以不用这个包裹元素,就是利用marginauto值,回忆一下我们以前水平居中都是怎么做的,是不是这样margin:0 automargin-leftmargin-right的默认值是0,如果设置为auto,将会根据剩余可用空间来计算,这也是为什么能水平居中,因为左右都想尽量多,那么就只能平分了,对于本示例,我们只给用户名flex子元素设置margin-left:auto,那么剩余空间将全部给它,也就相当于把用户块挤到右边去了:

flex大法:一网打尽所有常见布局

隔行交叉显示

flex大法:一网打尽所有常见布局

有时候为了不让布局太单调,即使一个列表是同类数据,展示上也会做成上述隔行交叉的样式,这个使用flex可以轻松的做到,给2n的行设置flex-direction: row-reverse即可让偶数行的主轴方向由默认的从左向右变成从右向左:

flex大法:一网打尽所有常见布局

此外也可以使用order属性,这个属性可以让flex子元素按order的数值大小来排序显示,我们可以默认左边的设为2,右边的设为3,然后在偶数行再给右边的设为1,自然就跑到前面去了:

flex大法:一网打尽所有常见布局

网格布局

此网格非grid布局,虽然网格列表用grid是最好的,但是本文的主角是flex,假设我们要实现下面这样一个列表:

flex大法:一网打尽所有常见布局

上述列表对flex来说是不擅长的,因为要带间距,所以不能简单的把子元素宽度设为25%,否则再加上外边距,一行肯定显示不下四个,那你可能会想,那我宽度就少一点好了,比如设为20%,然后允许扩展,即flex-grow:1,那样不就可以把减去子元素宽度及外边距还剩下的空间再还给子元素了吗,试试看:

flex大法:一网打尽所有常见布局

可以看到前面一切正常,但是最后一行因为只有一个元素,且设置了允许扩展,所以它被拉满整行了,这种效果显然不是我们要的。

其实我们可以使用内边距来做间距,设置一下子元素的box-sizing:border-box,让内边距包含在宽度内,这样就可以放心的把子元素的宽度设为25%了,当然这样的缺点是里面得再嵌套一个元素用来作为实际的内容容器。

flex大法:一网打尽所有常见布局

圣杯布局

flex大法:一网打尽所有常见布局

所谓圣杯布局如上所示,头尾高度固定,宽度占满,中间的内容部分分为三列,两侧宽度固定,高度占满,中间的内容部分随着浏览器宽度变化,其实就是我们上面讲过的【单列布局】的中间部分变成三列而已,实现完全没有啥特别的,以【单列布局】为基础,给content添加三个子元素,两侧定宽,并且不允许收缩,中间允许扩展即可:

flex大法:一网打尽所有常见布局

垂直居中

不知道各位最开始用flex是为什么,反正笔者就是冲着垂直居中去的,用它实在是太简单了,之前还考虑是不是定高呀,用什么定位呀,用flex就是两步,一让父元素变成弹性盒子,二设置交叉轴的元素排布方式为居中就完事了:

flex大法:一网打尽所有常见布局

如果还需要水平居中的话就再给容器元素设置主轴的排列方式为justify-content:center,现在连让文字居中我都是用flex,无情的抛弃了text-alignline-height

高度自动对齐

有些时候同一列的元素为了美观我们希望他们的高度是一样的,如果内容固定不变当然可以直接写死高度,但如果可变的话就不能写死了:

flex大法:一网打尽所有常见布局

这个场景使用flex完全不需要额外设置什么属性,只要给容器元素设置display:flex即可,因为flex容器有个属性align-items,用来设置flex子元素在交叉轴上如何对齐,默认值为stretch,即如果flex子元素未设置高度,那么将占满整个容器的高度,因为我们并没有给容器设置高度,所以容器的高度就是所有flex子元素里最大的高度。

flex大法:一网打尽所有常见布局

小结

本文以标题党的名义总结了部分常见布局使用flex的实现,要灵活使用flex还是需要理解它的一些属性的意义,此外也需要知道flex的边界在哪,哪些是它不擅长的。

本文总结的难免会有不全,或者有更好的实现,欢迎讨论。

点赞
收藏
评论区
推荐文章
待兔 待兔
10个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
菜园前端 菜园前端
2年前
想学会flex布局,我强烈推荐你来看看这篇文章!!
原文链接:为什么要使用flex布局?flex布局是目前比较流行的一种布局,因为它十分简单灵活,区区简单几行代码就可以实现各种页面的的布局,以前我在学习页面布局的时候我深受其float、display、position这些属性的困扰。使用flex属性就可以写
仲远 仲远
2年前
Termius for Mac(SSH客户端)
Termiusmac版是macOS平台上的一款最具创新性和最受欢迎的跨平台SSH客户端,通过此软件能够帮助我们对RaspberryPi,Linux机器及UNIX服务器群进行管理工作。其中在密钥以及密码的支持方面,软件提供了ECDSA和ed25519密钥以及chacha20poly1305密码,基本上日常使用的加密方式都包含其中,所以不用担心密钥不适配导致的链接不上的情况产生。除此之外软件还支持FTP/SFTP连接哦。
浩浩 浩浩
4年前
【Flutter实战】线性布局(Row、Column)
4.2线性布局(Row和Column)所谓线性布局,即指沿水平或垂直方向排布子组件。Flutter中通过Row和Column来实现线性布局,类似于Android中的LinearLayout控件。Row和Column都继承自Flex,我们将在弹性布局一节中详细介绍Flex。主轴和纵轴对于线性布局,有主轴和纵轴之分,如果
浩浩 浩浩
4年前
【Flutter 实战】Dart语言简介
1.4Dart语言简介在之前我们已经介绍过Dart语言的相关特性,读者可以翻看一下,如果读者已经熟悉Dart语法,可以跳过本节,如果你还不了解Dart,也不用担心,按照笔者经验,如果你有过其他编程语言经验(尤其是Java和JavaScript)的话会非常容易上手Dart。当然,如果你是iOS开发者,也不用担心,Dart中也有一些与Swift比较相似的特
Stella981 Stella981
3年前
IDEA Spring使用Swagger2 API接口
根据Swagger2可以快速帮助我们编写最新的API接口文档,再也不用担心开会前仍忙于整理各种资料了,间接提升了团队开发的沟通效率。1\.引入依赖<!Swagger2api接口插件<dependency<groupIdio.springfox</groupId
Wesley13 Wesley13
3年前
Java开发奇技淫巧
lombok 提供了简单的注解的形式来帮助我们简化消除一些必须有但显得很臃肿的java代码。特别是相对于POJO,有了它妈妈再也不用担心你的Entity啦.             lombok的官方网址:http://projectlombok.org/(https://www.oschina.net/action/GoToLi
Wesley13 Wesley13
3年前
Java源码解析之LinkedList源码剖析(基于JDK1.8)
    学过数据结构的都知道双端队列(链表),没学过的也没有关系,下面我先介绍一下双端队列(链表),为什么要介绍它了,因为LinkedList本质上就是一个双端队列(链表)。一. 双端队列(链表)的介绍1. 如下图:双端队列(链表)中单个节点对应的结构!(https://oscimg.oschina.net/oscn
Stella981 Stella981
3年前
Grid布局和Flex布局
Flex布局(弹性布局)Flex是弹性布局,用来为盒状模型提供最大的灵活性,任何一个容器都可以指定为Flex布局。行内元素也可以使用Flex布局。采用Flex布局的元素,称为Flex容器。flexitem项目是Flex布局的元素,简称项目。容器:水平的主轴(mainaxis)和垂直的交叉轴(crossaxis),单个项目占据的主轴空间叫做m
Stella981 Stella981
3年前
JavaScript的BOM和DOM
1,window对象,所有浏览器都支持window对象,它表示浏览器窗口BOM(browserObjectModel)是指浏览器对象模型,它使JavaScript有能力与浏览器进行"对话".DOM(DocumentObjectModel)是指文档对象类型,通过它,可以访问HTML文档的所有元素window对象客户端JavaScript最高
Wesley13 Wesley13
3年前
APP 验证码 采用MEMCAHED验证的坑
都知道APP不是用浏览器来的,所以验证码生成sessioncookie是行不通了。一开始APP进入验证码界面,先让他请求一次服务器,生成key:code返回去。再把拿到的KEY带到服务器上面去生成图片。同时生成一个key:code再把key返回到客户端,当客户端验证图片的时候再把key再到服务器上去获取key里的code进行对比。一旦对比成功放行,对比