• CSS - 弹性布局(flex)


    目录

    传统布局的不足之处:导航栏实现案例说明问题

    关于单个、一行多个浮动元素的水平居中实现

    弹性布局

    弹性容器的主轴和侧轴概念

    弹性容器的主轴对齐&侧轴对齐(一维布局特性说明)

    主轴flexitem元素弹性宽高,以及换行/换列

    多行对齐

    flex-flow复合样式属性

    flexbox样式总结

    flexitem专有样式说明

    flex-grow及按比扩容

    flex-shrink及按权重比压缩

    flex-basis

    flex复合写法

    order

    align-self


    传统布局的不足之处:导航栏实现案例说明问题

    CSS - 定位布局_伏城之外的博客-CSDN博客

    上一个章节定位布局的粘性定位小节中,实现工商银行导航栏时,我使用了ul li,并且由于li是块容器,所以不支持在同一行上排列。此时有两个传统方案可以让li在一行排列:

    • 将li转为行内块元素
    • 将li转为浮动元素

    但是这两个方案都有缺点:

    • 行内块元素之间会产生因为代码空格或换行导致的间隙,我们可以通过去除代码中行内块之间的空格、换行,来消除行内块元素之间的空隙,但是此时代码可读性就变差了
    • 浮动元素间虽然紧密贴合,但是会脱标,导致父元素ul的宽高塌陷,虽然给父元素加overflow:hidden,将父元素ul变为BFC容器可以解决宽高塌陷,但是此时父元素的内容区宽度是占满一行的,这将导致无法让父元素紧密包裹子浮动元素,导致无法带子浮动元素水平居中

    关于单个、一行多个浮动元素的水平居中实现

    首先浮动元素脱标后,浮动元素在浮动流中是不会占满一行的(即不会通过margin来占满剩余宽度),所以此时margin:0 auto无法让浮动元素实现水平居中。

    此时我们可以给浮动元素包裹一个标准流父元素,并设置宽高为子浮动元素宽高,之后margin:0 auto父元素。

     这种方法也适用于一行多个浮动元素的水平居中

    但是当浮动元素未设置宽高(即浮动元素宽高由其内容撑开)时,其标准流父元素的宽高设置将很难给定,而父元素宽高无法确定,则无法实现准确的父元素携带子浮动元素水平居中。

    那么此时我们需要怎么办呢?

    弹性布局

    Flexible Box 模型,通常被称为 flexbox,是一种一维的布局模型。它给 flexbox 的子元素之间提供了强大的空间分布和对齐能力。

    这里一维布局的意思指的是:flexbox的子元素只会按照行方向或者列方向,一个方向上进行布局。

    当我们为一个元素添加display:flex样式后,该元素就变为了flexbox,即弹性容器。flexbox的子元素就变为了flexitem,即弹性项目。

    弹性布局的弹性布局分别体现在:

    • 弹性:flexitem元素可以膨胀以填充额外的空间,收缩以适应更小的空间。
    • 布局:flexbox给予了flexitem强大的空间分布和对齐能力

    弹性容器上支持如下样式属性:

    • flex-flow:flex-direction flex-wrap
    • justify-content
    • align-items
    • align-content

    弹性项目上支持如下样式属性:

    • order
    • flex:flex-grow flex-shrink flex-basis
    • aligin-self

    弹性容器的主轴和侧轴概念

    我们知道弹性布局是一维布局,flexItem只会在flexbox的一个方向上进行布局,即flexbox的主轴方向。而flexbox的主轴的垂直方向就是flexbox的侧轴方向。

    flexbox的主轴并非固定是水平方向或垂直方向,而是取决于flexbox元素的flex-direction样式,flex-direction属性值如下:

    • row(默认)
    • row-reverse
    • colum
    • colum-reverse

    我们通过下图来理解这四个值得含义

     

    弹性容器的主轴对齐&侧轴对齐(一维布局特性说明)

    其实理论上来说,弹性布局是一维布局,弹性容器中的弹性项目flexitem只能在主轴上进行各种对齐。而flexitem元素在主轴上的各种对齐就是主轴对齐。侧轴对齐并不是针对每个flexitem元素的,而是针对整个主轴的。所以flexitem元素只在主轴上布局,弹性布局是一维布局。

    主轴对齐指的是:flexitem在flexbox主轴上的对齐方式

    侧轴对齐指的是:整个主轴在侧轴上的位置

    设置主轴上元素的对齐方式使用样式justify-content,它具有如下属性值:

    • flex-start(默认值)
    • center
    • flex-end
    • space-between
    • space-around

    下面通过代码看看以上对齐效果:

    justify-content:flex-start

    flexitem元素从flexbox容器的主轴起始线排列

    justify-content:center

    flexitem元素从flexbox容器的主轴中间排列

    justify-content:flex-end

    flexitem元素从flexbox容器的主轴终止线排列

    justify-content:space-around

    每个flexitem元素的左右空间相等

    justify-content:space-between

     flexitem元素之间间隔相等

    设置整个主轴在侧轴上的位置用样式align-items,它具有如下属性值:

    • stretch(默认值)
    • flex-start
    • center
    • flex-end
    • baseline

    下面通过代码看看以上属性值效果:

    align-items的默认值是stretch,含义是自动拉伸自适应高度的flexitem元素的高度为flexbox的高度

     对于设置高度height的flexitem元素而言,align-items不会拉伸其高度

    如果flexbox也没有高度,则flexbox会被高度最高的flexitem元素撑开,即flexbox的高度为最高的flexitem元素的高度。

    所以实际上,此时无高度的flexitem会默认被拉伸到最高的兄弟flexitem元素的高度

    主轴放置于侧轴起始位置 

    主轴放置于侧轴中间位置 

    主轴放置于侧轴结束位置 

    主轴上flexitem元素按照内容文字的基线baseline对齐

    主轴flexitem元素弹性宽高,以及换行/换列

    当我们主轴上flexitem过多,以至于超出flexbox宽/高时,默认情况下,主轴上的flexitem元素是不会换行的,而是表现出flexitem元素的弹性宽/高特点,即flexitem元素的会被尽可能地压缩宽/高以适应flexbox的宽/高,但是一个flexitem元素的宽度最多被压缩到内容宽高,如果flexitem压缩到内容宽高还是超过flexbox宽高的话,则默认会超出flexbox范围,而不是换行。

    我们可以通过flexbox容器样式属性 flex-wrap 来控制主轴上flexitem是否换行,flex-wrap属性值如下:

    • nowrap(默认值)
    • wrap
    • wrap-reverse

    当给flexbox设置flex-wrap:wrap后,此时主轴上flexitem元素的宽高不会再被压缩,当flexbox一行/一列放不下多余flexitem时,则对应flexitem换行或换列显示。 

    换行/换列时,如果flexbox在对应换行/换列方向上有剩余空间,默认情况下剩余空间会被均分,保证每个flex-item的在对应方向的边距相同。

    但是如果我们设置了侧轴对齐方式,则

    当flexbox设置了flex-wrap:wrap,即使主轴换行/换列也放不下多余的flexitem,flexitem也不会被被压缩宽高,而是超出flexbox范围。

    flex-wrap:wrap-reverse是反向换行

    需要注意的是 flex-direction:xxx;flex-wrap:wrap-reverse 不等价于 flex-direction:xxx-reverse; flex-wrap:wrap; 

     原因是:flex-wrap控制的是换行/换列的方向,而不是主轴的方向

    多行对齐

    上例中,我们可以通过align-items来设置多行的在侧轴上的对齐方式

    但是可以发现,align-items设置的多行对齐,行与行之间总是留有空隙。

    如果我们想让多行之间没有空隙的实现在侧轴上对齐,则需要借助flexbox的align-content样式。

    首先,需要点明的是,align-content只能用于多行侧轴对齐设置,即只能用于flex-wrap:wrap的flexbox。

    align-content从名字上看,其实就是将每一行或每一列当成一个整体元素,在flexbox侧轴上排列(让他们像主轴上的flexitem一样实现对齐),align-content具有如下常用属性值:

    • normal(默认值)
    • flex-start
    • center
    • flex-end
    • baseline
    • space-around
    • space-between

    当align-content为normal时,则多行根据align-items值在侧轴上对齐; 

    当align-content不是normal时,则多行根据lign-content值在侧轴上对齐;

    flex-flow复合样式属性

    flex-direction和flex-wrap可以复合写成flex-flow样式;

    flex-flow:flex-direction flex-wrap

    由于flex-direction的默认值是row,flex-wrap的默认值是nowrap,所以flex的默认值是:

    flex-flow:row nowrap;

    flexbox样式总结

    我们通过给flexbox设置flex-direction来控制其主轴方向,设置flex-wrap来设置其是否换行,二者可以复合写为flex-flow。

    主轴上flexitem元素的对齐使用justify-content,主轴行在侧轴上的位置用align-items,对于主轴多行情况,还可以将每一行当成整体元素使用align-content使其在侧轴上实现对齐。

    flexitem专有样式说明

    flexitem即flexbox在主轴上的弹性项目元素,当我们设置flexbox不换行时,flexitem元素的宽/高会具有弹性,下面以主轴row方向来说明:

    • 当flexbox一行放不下所有flexitem元素,则所有flexitem的宽度会被自动压缩到可以适配一行宽度位置,但是最小只能压缩到flexitem的内容宽度。
    • 当align-items为stretch时,对于未设置高度的flexitem来说,其高度会被拉伸到flexbox的高度。

    这里我们发现通过flexbox样式来控制flexitem元素的弹性是普渡众生型的,所有flexitem元素都会被影响,如果我们想让部分flexitem的宽度不被压缩,则需要针对特定的flexitem元素进行设置,此时我们需要使用flexitem专有样式flex-grow,flex-shrink,flex-basis

    另外,flexbox只会按照代码顺序来排列flexitem,这是不自由的,所以我们需要使用flexitem专有样式order来针对每个flexitem元素设置排列顺序。

    还有,flexbox是通过align-items来控制所有flexitem在侧轴上的对齐,也是普渡众生型的,为了能实现特定flexitem的侧轴对齐,我们可以使用align-self,该样式的值和align-items一致,但是只作用于特定flexitem,而不是所有flexitem。

    flex-grow及按比扩容

    MDN官方对于flex-grow的解释是:设置flexitem主尺寸的弹性增长系数。

    flexitem的主尺寸指的是flexitem在主轴方向上的尺寸,

    • 比如主轴为row或row-reverse时,flexitem的主尺寸就是宽度width;
    • 比如主轴为colum或colum-reverse时,flexitem的主尺寸就是高度height;

    弹性增长系数,其实就是当flexbox主轴方向存在剩余空间时,设置了flex-grow的flexitem主尺寸可以分配到的剩余空间的比例。

    flex-grow可是任何非负数值,默认值为0。

    flex-grow按比扩容计算规则:

    假设:flexbox主轴方向是row,则

    剩余宽度 = flexbox宽度 -  所有flexitem原始宽度之和

    flexitem占比 = flexitem的flex-grow  ÷  所有flexitem的flex-grow之和

    flexitem所分得的剩余宽度 = flexitem占比 × 剩余宽度

    flexitem弹性宽度 = flexitem原始宽度 + flexitem所分得的剩余宽度

    剩余宽度 = 500 - (100 + 150 + 50) = 200px

    blue占比 = 0 / (0 + 1 + 1) = 0

    red占比 = 1 / (0 + 1 + 1) = 1/2

    orange占比 = 1 / (0 + 1 + 1) = 1/2

    blue所分得剩余宽度 = 0 * 200 = 0

    red所分得剩余宽度 = 1/2 * 200 = 100

    orange所分得剩余宽度 = 1/2 * 200 = 100

    blue未扩容

    red扩容后弹性宽度为 150 + 100 = 250px

    orange扩容后弹性看到为 50 + 100 = 150px

    flex-shrink及按权重比压缩

    MDN官网对于flex-shrink的定义是: 该属性指定了flexitem的收缩规则。flexitem仅在默认宽度之和大于flexbox容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值。

    flexitem元素的flex-shrink值可以为任何非负数,默认值为1。

    flex-shrink按权重比压缩计算规则:

    假设:flexbox主轴方向是row,则

    flexitem权重 = flexitem宽度 × flexitem的flex-shrink系数

    总权重 = 所有flexitem的权重之和

    flexitem权重比 = flexitem权重 ÷ 总权重

    总压缩宽度 = 所有flexitem原始宽度之和 - flexbox宽度

    flexitem压缩宽度 = flexitem权重比 × 总压缩宽度

    flexitem弹性宽度 = flexitem原始宽度 - flexitem压缩宽度

    flexitem的flex-shrink默认为1。

    总权重 = (100 * 0 + 150 * 1 + 50 * 1) * 2 = 400

    blue权重比 = 100 * 0 / 400 = 0

    red权重比 = 150 * 1 / 400 = 3/8

    orange权重比 = 50 * 1 / 400 = 1/8

    总压缩宽度 = 600 - 500 = 100

    blue压缩宽度 = 0 * 100 = 0

    red压缩宽度 = 3/8 * 100 = 37.5

    orange压缩宽度 = 1/8 * 100 = 12.5

    blue未被压缩

    red弹性宽度 = 150 - 37.5 = 112.5

    orange弹性宽度 = 50 - 12.5 = 37.5

    flex-basis

    MDN官方对于flex-basis的解释是:flexitem在主轴方向上的初始大小。如果不使用box-sizing:border-box盒子模型的话,那么flex-basis指定的就是flexitem的内容区主尺寸。

    如果一个flexitem元素既设置了flex-basis(非auto值),又设置了内容区主尺寸(即content-box的width、height),则flexitem的内容区尺寸以flex-basis的值为准。

    flex-basis的取值如下:

    • auto(默认值)
    • 指定尺寸
    • content

    flex-basis:auto的意思是“参照我的width/height属性”,即flexitem的内容区尺寸取决于width\height。

    flex-basis:content,意思是参照flexitem元素实际内容的尺寸

     flex-basis:指定尺寸,意识是忽略flexitem的主尺寸width/height,以flex-basis指定的尺寸为准

    另外由于flex-basis会影响flexitem的主尺寸大小,所以会影响剩余宽度计算,压缩宽度计算,即会影响flex-grow,flex-shrink。

    剩余宽度 = 200 - 85 - 50 - 50 = 15px

    blue扩容后宽度 = 50 + 15 = 65px

    每个flexitem的flex-shrink默认为1

    压缩总宽度 = flexitem原始宽度之和 - flexbox宽度 = (85 + 50 + 50) * 2 - 200 = 170

    总权重 = (85 * 1 + 50 * 1 + 50 * 1) * 2 = 370

    red权重比为 85 * 1 / 370

    blue权重比为 50 * 1 / 370

    green权重比为 50 * 1 / 370

    压缩宽度 = 压缩总宽度 * 权重比

    则red弹性宽度为 = 原始宽度 - 压缩宽度 = 45.95px

    flex复合写法

    flex-grow、flex-shrink、flex-basis可以复合写成flex样式属性。

    flex:flex-grow  flex-shrink  flex-basis

    但是flex的用法多种多样,其支持一个值,两个值,三个值的情况

    对于一个值的情况

    如果值为非负数字,且无单位,则该值对应flex-grow,且此时flex-shrink:1,flex-basis为0%

     

    如果值为一个有单位的数字,则带单位的数字对应flex-basis的值,且此时flex-grow:1,flex-shrink:1

     如果值为auto或content,则也对应flex-basis的值,且此时flex-grow:1,flex-shrink:1

     对于两个值的情况

    此时第一个值必然对应flex-grow,则只能是非负数。

    第二值可以是flex-shrink,比如为非负数时,也可以时flex-basis,比如为带单位的值,auto,content。

    对于三个值的情况

    则必然对应 flex:flex-grow  flex-shrink  flex-basis

    总结

    flex

    flex-grow

    (默认1)

    flex-shrink

    (默认1)

    flex-basis

    (默认0%)

    0010%
    1110%
    auto11auto
    content11content
    30px1130px
    1 1110%
    1 auto11auto
    1 1 auto11auto

    order

    flexitem元素还支持设置order样式来定义自身排列顺序,order值越小越靠前,order值默认为0,所以设置了正数的order的lfexitem总是显示在未设置order的flexitem后面。order还支持负数,order为负数的flexitem总是最先显示,因为它小于默认的order:0。

    align-self

    align-self用于给特定的flexitem进行侧轴对齐,其值基本与align-items值相同。并且flexitem的align-self会覆盖来自flexbox的align-items。

    align-self的值如下:

    • flex-start
    • center
    • flex-end
    • baseline

  • 相关阅读:
    阿里云国际站优势有哪些?使用起来方便吗?
    智慧园区软件平台设计方案Word(1129页)
    cobbler Centos7
    入门人工智能 ——自然语言处理介绍,并使用 Python 进行文本情感分析(5)
    官宣出自己的博客啦
    LCR 059.数据流中的第 K 大元素
    平板有必要买触控笔吗?推荐的ipad手写笔
    [附源码]SSM计算机毕业设计在线购物系统JAVA
    "嫦娥奔月",难道古人早已看透一切?
    简单易修改的弹框组件
  • 原文地址:https://blog.csdn.net/qfc_128220/article/details/125889851