CSS-Flex布局

287 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

现在来总结总结CSS的Flex布局吧(前两天面试被问了,发现有一些我都忘了...)

Flex盒子

要使用flex布局,首先得有flex的弹性盒子。这很简单,只需要将要转为弹性盒子的盒子使用display:flex;就可以了。

div {
    display:flex;
}

变为弹性盒子之后,弹性盒子的子元素的float、clear和vertical-align属性将失效。

将盒子变为弹性盒子之后,我们一般将弹性盒子称之为“容器”,容器有两条轴,一条是主轴,一条是交叉轴,默认是以行为主轴,与主轴垂直的为交叉轴。

flex-direction

flex-direction可以改变主轴的方向。

div {
    display: flex;
    flex-direction: row;     //(默认值)主轴为水平方向,起点在左端。
    flex-direction: row-reverse;    //主轴为水平方向,起点在右端。
    flex-direction: column;  //主轴为垂直方向,起点在上沿。
    flex-direction: column-reverse;  //主轴为垂直方向,起点在下沿。
}

为row时:

image.png 为 row-reverse时:

image.png 为column时:

image.png 为column-reverse时:

image.png

flex-wrap

该属性的意思是是否换行,当主轴满了之后,如果不换行,容器里的元素就会在一行内进行压缩(默认情况下)。默认情况下是不换行的,也就是说默认为flex-wrap:nowrap;

nowrap (默认值) 不换行压缩宽度
wrap 换行
wrap-reverses 反向换行

<!DOCTYPE html>
<html lang="en">

<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>
        * {
            padding: 0;
            margin: 0;
        }
        
        div {
            width: 200px;
            height: 200px;
            display: flex;
            flex-direction: row;
            background-color: #ddd;
            margin: auto;
            flex-wrap: wrap;
        }
        
        li {
            width: 100px;
            height: 100px;
            list-style: none;
            background-color: red;
            color: white;
            font-size: 20px;
            padding: 10px;
            box-sizing: border-box;
            background-clip: content-box;
        }
        
        li:nth-child(2n) {
            background-color: blue;
        }
    </style>
</head>

<body>
    <div>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </div>
</body>

</html>

image.png

我们可以发现,我们设置容器里的元素宽为100px,但是容器只有200px,那么元素就会被压缩。

如果我们设置为wrap:

image.png

设置为wrap-reverses:

image.png

flex-flow

这就是将flex-direction和flex-wrap进行合并了。

flex-low: [flex-direction] [flex-wrap]

justify-content

主轴元素对齐方式

flex-start (默认)靠着main-start对齐//参考常见术语(一般是左方向)
flex-end 靠着main-end对齐//参考常见术语(一般是右方向)
center 靠着主轴居中对齐//一般就是居中对齐
space-between 两端对齐,靠着容器壁,剩余空间平分
space-around 分散对齐,不靠着容器壁,剩余空间在每个项目二侧平均分配
space-evenly 平均对齐,不靠着容器壁,剩余空间平分

flex-start image.png flex-end

image.png center

image.png space-between

image.png space-around

image.png space-evenly

image.png

align-items

交叉轴对齐方式 单行

flex-start:交叉轴的起点对齐。
flex-end:交叉轴的终点对齐。
center:交叉轴的中点对齐。
baseline: 项目的第一行文字的基线对齐。
stretch(默认值)伸展:如果项目未设置高度或设为auto,将占满整个容器的高度。

flex-start

image.png flex-end

image.png center

image.png baseline

image.png stretch

image.png

align-content

交叉轴行对齐方式 多行

flex-start (每一行)(默认)靠着cross-start对齐//参考常见术语(一般是左方向)
flex-end (每一行)靠着cross-end对齐//参考常见术语(一般是右方向)
center (每一行)靠着cross线居中对齐//一般就是居中对齐
space-between (每一行)两端对齐,靠着容器上下壁,剩余空间平分
space-around (每一行)分散对齐,不靠着容器壁,剩余空间在每个项目二侧平均分配
strentch (每一行)伸缩,占满整个高度

当行数是多行时,align-items也就实效了,我们就得将align-items换为align-content。align-content的使用方式基本和justify-content 属性一模一样。

<!DOCTYPE html>
<html lang="en">

<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>
        * {
            padding: 0;
            margin: 0;
        }
        
        div {
            width: 300px;
            height: 400px;
            display: flex;
            flex-direction: row;
            background-color: #ddd;
            margin: auto;
            flex-wrap: wrap;
            /* justify-content: center; */
            align-items: center;
        }
        
        li {
            width: 100px;
            height: 100px;
            list-style: none;
            background-color: red;
            color: white;
            font-size: 20px;
            padding: 10px;
            box-sizing: border-box;
            background-clip: content-box;
            border: 1px solid black;
        }
        
        li:nth-child(2n) {
            background-color: blue;
        }
    </style>
</head>

<body>
    <div>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </div>
</body>

</html>

image.png

我们发现使用align-items这并没有达到我们想要的效果,我们的居中应该是两行都在最中间。这时我们就需要使用align-content: center;

align-content: center

image.png

space-between

image.png

space-around

image.png

flex-start

image.png

flex-end

image.png

stretch(子元素高度得设置0或者aoto)

image.png

上面的属性都是作用于父盒子(也就是弹性容器上面),下面的属性都是作用于项目元素.

align-self

该属性可覆盖容器的align-items, 用以自定义某个项目的对齐方式

<!DOCTYPE html>
<html lang="en">

<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>
        * {
            padding: 0;
            margin: 0;
        }
        
        div {
            width: 500px;
            height: 400px;
            display: flex;
            flex-direction: row;
            background-color: #ddd;
            margin: auto;
            flex-wrap: wrap;
            align-items: center;
        }
        
        li {
            width: 100px;
            height: 100px;
            list-style: none;
            background-color: red;
            color: white;
            font-size: 20px;
            padding: 10px;
            box-sizing: border-box;
            background-clip: content-box;
            border: 1px solid black;
        }
        
        li:nth-child(2n) {
            background-color: blue;
        }
    </style>
</head>

<body>
    <div>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </div>
</body>

</html>

image.png

现在我们重写第一个li的align-self

  li:first-child {
            align-self: flex-start;
        }

image.png

此外还有:

auto(默认值):继承父类
flex-start 与交叉轴起始线对齐
flex-end 与交叉轴终止线对齐
center 与交叉轴中间线对齐: 居中对齐
stretch 在交叉轴方向上拉伸
baseline 与基线对齐(与内容相关用得极少)

这里就不多赘述了。

flex-grow

  • 在容器主轴上存在剩余空间时, flex-grow才有意义
  • 该属性的值,称为放大因子, 常见的属性值如下:
序号属性值描述
10默认值不放大,保持初始值
2initial设置默认值,与0等效
3n放大因子: 正数

最开始:

<!DOCTYPE html>
<html lang="en">

<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>
        * {
            padding: 0;
            margin: 0;
        }
        
        div {
            width: 500px;
            height: 400px;
            display: flex;
            flex-direction: row;
            background-color: #ddd;
            margin: auto;
            flex-wrap: wrap;
            align-items: center;
        }
        
        li {
            width: 100px;
            height: 100px;
            list-style: none;
            background-color: red;
            color: white;
            font-size: 20px;
            padding: 10px;
            box-sizing: border-box;
            background-clip: content-box;
            border: 1px solid black;
        }
        
        li:nth-child(2n) {
            background-color: blue;
        }
    </style>
</head>

<body>
    <div>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </div>
</body>

</html>

image.png

加了以下代码后:

        li:nth-child(1) {
            flex-grow: 0;
        }
        
        li:nth-child(2) {
            flex-grow: 1;
        }
        
        li:nth-child(3) {
            flex-grow: 3;
        }
        
        li:nth-child(4) {
            flex-grow: 1;
        }

image.png

查看F12后,发现第一个li宽为100px,第二个为120px,第三个为160px,第四个为120px。

这是咋算的呢?

因为我们父盒子为500px,字元素li宽度为100px,那么还剩100px没有使用。然后第二个li占剩余空间的1份,第三个li占剩余空间的3份,第四个li占剩余空间的1份,就是把剩余空间分为5份,就是100/5=20px,也就是一份为20px,那么第二个li宽就是本身的100px加上剩余空间的1份,也就成了120px。以此类推就可以了。

flex-sharink

  • 当容器主轴 “空间不足” 且 “禁止换行” 时, flex-shrink才有意义
  • 该属性的值,称为收缩因子, 常见的属性值如下: 序号 | 属性值 | 描述 | | -- | --------- | -------------- | | 1 | 1默认值 | 允许项目收缩 | | 2 | initial | 设置初始默认值,与 1 等效 | | 3 | 0 | 禁止收缩,保持原始尺寸 | | 4 | n | 收缩因子: 正数 默认效果(默认情况下fkex-sharink为1):
<!DOCTYPE html>
<html lang="en">

<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>
        * {
            padding: 0;
            margin: 0;
        }
        
        div {
            width: 300px;
            height: 400px;
            display: flex;
            flex-direction: row;
            background-color: #ddd;
            margin: auto;
            align-items: center;
        }
        
        li {
            width: 100px;
            height: 100px;
            list-style: none;
            background-color: red;
            color: white;
            font-size: 20px;
            box-sizing: border-box;
        }
        
        li:nth-child(2n) {
            background-color: blue;
        }
    </style>
</head>

<body>
    <div>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </div>
</body>

</html>

image.png

当我们给所有的li加上flex-sharink后:

image.png

元素不会进行缩小,而会超出容器。那么我们给一部分加上呢?

        li:nth-child(1) {
            flex-shrink: 0;
        }
        
        li:nth-child(2) {
            flex-shrink: 1;
        }
        
        li:nth-child(3) {
            flex-shrink: 0;
        }
        
        li:nth-child(4) {
            flex-shrink: 3;
        }

image.png

我们发现第一个li宽度为100px,第二个li宽度为75px,第三个li的宽度为100px,第四个li的宽度为25px。

这是因为:盒子宽度为300px,四个子元素加起来为400px,超出了100px。然后按照比例缩小到这些元素上 100/4 = 25px。第一个不缩小,第二个li缩小251 = 25px,那么还剩下100-25=75px,第四个li缩小253=75px,还剩下100-75=25px。

flex-basis

flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

它可以设为跟widthheight属性一样的值(比如350px),则项目将占据固定空间。他的优先级比宽高要高。就是同时设置宽高后,主轴会根据flex-basis的值而不会按照宽高值。

flex

flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto,也就是三个属性的默认值,后两个属性可选

比较常见的是flex: 1 ,其相当于1 1 0%,即等分父元素剩余空间,等比例缩小,不占据固定空间

所以flex: 1 后,即使父元素设置flex:wrap,所有项目还是处于一行,且会等比例缩小,即使为项目(子元素)设置了固定宽度,还是会缩小于设置的width,因为不仅flex-shrink为1,且 flex-basis为0%

如果使用flex属性,修改第三个参数flex-basis的值即可设置最小固定宽度,且无需再设置宽

order

就是将元素重新排序

。。。

还差一点点,明天来补上。