前言

弹性盒子(Flexible Box,通常简称为 flexbox)布局是一种一维的布局模型。它的主要特点是给子元素提供了强大的空间分布和对齐能力。

$$tip

flex 布局已被浏览器全面支持,加上其强大的布局能力,现在网络上技术栈较新的网站都大量采用 flex 布局。比如:b 站、知乎等等。因此对于 flex 的知识点要求熟练掌握。

$$

基础概念和术语

由于 flexbox 是一个整套布局方案的代称,并不单指某个样式属性。整个方案里面会涉及到很多东西,先通过下图进行理解有助于之后的学习。

image

  • 容器(flex container):容纳所有 flex 子项的父元素被称为 flex 容器,容器的 display 样式为 flex 或 inline-flex。
  • 子项(flex item):容器的第一级子元素,会被进行分布或排列对齐。
  • 主轴(main axis):子项排列的轴向被称为主轴。
  • 交叉轴(cross axis):与主轴垂直的轴向被称为交叉轴。
  • 主轴长度(main size):主轴的长度。
  • 交叉轴长度(cross size):交叉轴的长度。

Flexbox 布局讲解

在以下的例子中,我们创建了一个 flex 容器,而且没有添加任何属性配置。它有着三个子项,这些子项安静地排成了一行。这便是一个最简单的 flex 布局,以下学习的所有属性配置不过是调整子项的排列对齐方式。

$$tip

块级元素作为 flex 子项时宽度会等于内容的宽度。

$$

<iframe height="300" style="width: 100%" scrolling="no" title="flexbox" src="https://codepen.io/3yya/embed/ZEabGdz?default-tab=html%2Cresult&editable=true&theme-id=light" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"></iframe>

常用场景

垂直居中

垂直居中是一个很常见的应用,参见登录框垂直对齐实例。同时元素垂直居中一直是一个难点,而弹性盒子的出现很轻松地解决了这个问题。

以下实例中设置容器的 align-items: center 使得子项在交叉轴上居中。

<div class="container">
    <div class="box"></div>
</div>
<style>
    .container {
        height: 200px;
        background-color: pink;
        display: flex;
        align-items: center;
    }

    .box {
        width: 50px;
        height: 50px;
        background-color: teal;
    }
</style>

$$demo

<div class="container">

<div class="box"></div>

</div>

<style>

.container {

height: 200px;

background-color: pink;

display: flex;

align-items: center;

}

.box {

width: 50px;

height: 50px;

background-color: teal;

}

</style>

$$

垂直居中对齐

之前的代码中都是设置待对齐元素 vertical-align: middle; 的方式对行内元素实现垂直居中对齐,略显麻烦。

以下实例中设置容器的 align-items: center 使得子项在交叉轴上居中。

<div class="container">
    <div class="box"></div>
    <div class="box2"></div>
    <div class="box3"></div>
</div>
<style>
    .container {
        height: 200px;
        background-color: pink;
        display: flex;
        align-items: center;
    }

    .box {
        width: 50px;
        height: 50px;
        background-color: teal;
    }
    .box2 {
        width: 100px;
        height: 150px;
        background-color: green;
    }
    .box3 {
        width: 80px;
        height: 100px;
        background-color: yellow;
    }
</style>

$$demo

<div class="container">

<div class="box"></div>

<div class="box2"></div>

<div class="box3"></div>

</div>

<style>

.container {

height: 200px;

background-color: pink;

display: flex;

align-items: center;

}

.box {

width: 50px;

height: 50px;

background-color: teal;

}

.box2 {

width: 100px;

height: 150px;

background-color: green;

}

.box3 {

width: 80px;

height: 100px;

background-color: yellow;

}

</style>

$$

水平居中

在之前经常使用以下方式对元素水平居中:

  • 行内元素:父元素设置 text-align: center;
  • 块级元素:设置 margin: 0 auto;

现在则有了以下的方式,通过设置容器的 justify-content: center 可以让子项在主轴上居中排列。

$$tip

flex-direction: row 时主轴为水平方向, flex-direction: column 时主轴为垂直方向。 $$

<div class="container">
    <div class="box"></div>
    <div class="box2"></div>
</div>
<style>
    .container {
        background-color: pink;
        display: flex;
        justify-content: center;
    }

    .box {
        width: 50px;
        height: 50px;
        background-color: teal;
    }
    .box2 {
        width: 100px;
        height: 50px;
        background-color: yellow;
    }
</style>

$$demo

<div class="container">

<div class="box"></div>

<div class="box2"></div>

</div>

<style>

.container {

background-color: pink;

display: flex;

justify-content: center;

}

.box {

width: 50px;

height: 50px;

background-color: teal;

}

.box2 {

width: 100px;

height: 50px;

background-color: yellow;

}

</style>

$$

两端对齐

两端对齐是最常见的场景之一,导航栏经常就是两端对齐, 参见一个导航栏两端对齐的实例。一个之前介绍过使用 float 实现两端对齐的方式,但使用 flex 实现起来将会更加优雅。

以下通过设置容器的 justify-content: space-between 使其实现了主轴两端对齐。

<div class="container">
    <div class="box"></div>
    <div class="box2"></div>
</div>
<style>
    .container {
        background-color: pink;
        display: flex;
        justify-content: space-between;
    }

    .box {
        width: 50px;
        height: 50px;
        background-color: teal;
    }
    .box2 {
        width: 100px;
        height: 50px;
        background-color: teal;
    }
</style>

$$demo

<div class="container">

<div class="box"></div>

<div class="box2"></div>

</div>

<style>

.container {

background-color: pink;

display: flex;

justify-content: space-between;

}

.box {

width: 50px;

height: 50px;

background-color: teal;

}

.box2 {

width: 100px;

height: 50px;

background-color: teal;

}

</style>

$$

弹性伸缩

有时需要某个元素占满剩余的空间,比如这个弹性搜索框实例

<div class="container">
    <div class="box"></div>
    <div class="flex-box"></div>
    <div class="box2"></div>
</div>
<style>
    .container {
        display: flex;
    }

    .box {
        width: 50px;
        height: 50px;
        background-color: teal;
    }
    .flex-box {
        flex: 1;
        background-color: yellow;
    }
    .box2 {
        width: 100px;
        height: 50px;
        background-color: teal;
    }
</style>

$$demo

<div class="container">

<div class="box"></div>

<div class="flex-box"></div>

<div class="box2"></div>

</div>

<style>

.container {

display: flex;

}

.box {

width: 50px;

height: 50px;

background-color: teal;

}

.flex-box {

flex: 1;

background-color: yellow;

}

.box2 {

width: 100px;

height: 50px;

background-color: teal;

}

</style>

$$

容器属性

容器属性部分包括了所有跟 flex 有关的作用于容器的属性样式。

display

定义 flex 容器。

  • flex:定义元素为弹性盒子容器。
  • inline-flex:定义元素为行内弹性盒子容器。

$$tip

flex 与块级元素类似,特性如下:

  • 默认占满父元素内容区域。
  • 独占一行。

inline-flex 与行内块元素类似,特性如下:

  • 默认宽度为内容宽度。
  • 可与其他行内元素共处一行。

$$

修改以下样例的 display 属性,观察下窗口背景色的宽度理解它们的区别。

<iframe height="300" style="width: 100%" scrolling="no" title="flexbox" src="https://codepen.io/3yya/embed/MWOaaZb?default-tab=css%2Cresult&editable=true&theme-id=light" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"></iframe>

justify-content

定义了子项沿主轴的对齐方式,有以下常用属性值:

  • flex-start(默认):起始线对齐。
  • flex-end:终止线对齐。
  • center:居中对齐。
  • space-between:子项均匀分布,两端对齐。
  • space-around:子项均匀分布,两端间距与其余间距一半。
  • space-evenly:子项均匀分布,两端间距为其余间距一致。

image

align-items

定义子项在交叉轴上的对齐方式,有以下取值:

  • stretch:默认值,未设置尺寸的元素将被拉伸至交叉轴长度(cross size)。
  • flex-start:交叉轴开始处(cross start)对齐。
  • flex-end:交叉轴结束处(cross end)对齐。
  • center:交叉轴中部对齐。
  • baseline:交叉轴上基线对齐。

image

flex-direction

决定了主轴的方向。

  • row(默认):水平方向。
  • row-reverse:水平方向,反向。
  • column:垂直方向。
  • column-reverse:垂直方向,反向。

image

以下实例设置了 flex-directionrow-reverse ,可见子项元素是从右至左排列的。试着修改

flex-direction 为其他值看看效果。

<iframe height="300" style="width: 100%" scrolling="no" title="flexbox" src="https://codepen.io/3yya/embed/WNXQQBQ?default-tab=css%2Cresult&editable=true&theme-id=light" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"></iframe>

flex-wrap

定义子项目在超过一行时是否换行。

  • nowrap(默认值):不换行。
  • wrap:子项将会换行,从上至下。
  • wrap-reverse:子项将会换行,从下至上。

以下实例将 flex-wrap 设置为 wrap-reverse ,可以看到是从下至往上排列。

<iframe height="300" style="width: 100%" scrolling="no" title="flexbox" src="https://codepen.io/3yya/embed/dyZYGNa?default-tab=css%2Cresult&editable=true&theme-id=light" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"></iframe>

flex-flow

flex-directionflex-wrap 的合并写法。

例: flex-flow: column wrap;

gap

定义了子项的间距。

<div class="container">
    <div class="item">a</div>
    <div class="item">b</div>
    <div class="item">c</div>
    <div class="item">d</div>
    <div class="item">e</div>
    <div class="item">f</div>
    <div class="item">g</div>
</div>
<style>
    .container {
        display: flex;
        background-color: #ccc;

        max-width: 300px;
        flex-wrap: wrap;

        /* 子项的间距 */
        gap: 20px;
    }
    .item {
        background-color: #048888;
        padding: 10px 20px;
        color: white;
        font-size: 20px;
        font-weight: bold;
    }
</style>

$$demo

<div class="container"> <div class="item">a</div> <div class="item">b</div> <div class="item">c</div> <div class="item">d</div> <div class="item">e</div> <div class="item">f</div> <div class="item">g</div> </div> <style> .container { display: flex; background-color: #ccc;

    max-width: 300px;
    flex-wrap: wrap;

    /* 子项的间距 */
    gap: 20px;
}
.item {
    background-color: #048888;
    padding: 10px 20px;
    color: white;
    font-size: 20px;
    font-weight: bold;
}

</style>

$$

子项属性

order

默认情况下,子项顺序按照元素的顺序排列,也可以用 order 改变它们的顺序。默认子项的 order0,按从小到大的顺序排序。

<iframe height="300" style="width: 100%" scrolling="no" title="flexbox" src="https://codepen.io/3yya/embed/xxPwVpb?default-tab=css%2Cresult&editable=true&theme-id=light" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"></iframe>

flex-grow

定义子项的弹性增长权重,决定了在主轴上存在剩余空间时,子项增长的权重系数,默认值为 0

计算公式:

元素长度 = 设定长度 + 增长长度

增长长度 = 剩余长度 * 权重占比

权重占比 = 自身权重 / 总权重

自身权重 = flex-grow

得到:元素长度 = 设定长度 + 剩余长度 * flex-grow / 总权重

假设:存在 a、b 两个子项目,主轴空间剩余 100px。

a:
flex-grow:3;
width: 100px;
总权重 = 3 + 1(b 的权重)= 4
权重占比 = 3/4
元素长度 = 100px(设定长度)+ 100px(剩余长度)* 3/4(权重占比) = 175px

b:
flex-grow:1;
width: 200px;
总权重 = 1 + 3(a 的权重)= 4
权重占比 = 1/4
元素长度 = 200px(设定长度)+ 100px(剩余长度)* 1/4(权重占比) = 225px
<div class="container">
    <div class="a"></div>
    <div class="b"></div>
</div>
<style>
    .container {
        display: flex;
        width: 400px;
        height: 100px;
        background-color: gray;
    }
    .a {
        width: 100px;
        background-color: yellow;
        flex-grow: 3;
    }
    .b {
        width: 200px;
        background-color: teal;
        flex-grow: 1;
    }
</style>

$$demo

<div class="container">

<div class="a"></div>

<div class="b"></div>

</div>

<style>

.container {

display: flex;

width: 400px;

height: 100px;

background-color: gray;

}

.a {

width: 100px;

background-color: yellow;

flex-grow: 3;

}

.b {

width: 200px;

background-color: teal;

flex-grow: 1;

}

</style>

$$

flex-shrink

定义子项的弹性收缩权重,决定了在主轴上发生溢出时,子项收缩的权重系数,默认值为 1 。与 flex-grow 不同的是,权重的计算还与自身设定的长度有关。

计算公式:

元素长度 = 设定长度 - 收缩长度

收缩长度 = 溢出长度 * 权重占比

权重占比 = 自身权重 / 总权重

自身权重 = 设定长度 * flex-shrink

得到:元素长度 = 设定长度 - 溢出长度 * (设定长度 * flex-shrink)/ 总权重

假设:存在 a、b 两个子项目,主轴空间溢出 100px。

a:
flex-shrink:6;
width:100px;  
自身权重 = 100(设定长度)*  6(flex-shrink)= 600
总权重 = 600 + 400(b 的权重)= 1000
权重占比 = 600 / 1000 = 3/5
元素长度 = 100px(设定长度) - 100px(溢出长度) * 3/5(权重占比) = 40px

b:
flex-shrink:1;
width:400px;  
自身权重 = 400(设定长度)*  1(flex-shrink)= 400
总权重 = 400 + 600(a 的权重)= 1000
权重占比 = 400 / 1000 = 2/5
元素长度 = 400px(设定长度) - 100px(溢出长度) * 2/5(权重占比) = 360px
<div class="container">
    <div class="a"></div>
    <div class="b"></div>
</div>
<style>
    .container {
        display: flex;
        width: 400px;
        height: 100px;
        background-color: gray;
    }
    .a {
        width: 100px;
        background-color: yellow;
        flex-shrink: 6;
    }
    .b {
        width: 400px;
        background-color: teal;
        flex-shrink: 1;
    }
</style>

$$demo

<div class="container">

<div class="a"></div>

<div class="b"></div>

</div>

<style>

.container {

display: flex;

width: 400px;

height: 100px;

background-color: gray;

}

.a {

width: 100px;

background-color: yellow;

flex-shrink: 6;

}

.b {

width: 400px;

background-color: teal;

flex-shrink: 1;

}

</style>

$$

$$warning

默认情况下 flex-shrink 不能收缩小于内容于主轴上的长度。如果要使其收缩小于内容的长度,需要设置以下值:

  • min-width: 0 (主轴为水平方向时)
  • min-height: 0 (主轴为垂直方向时)
  • overflow: hidden (或任何其他值,除了 visible

参考资料:Why don't flex items shrink past content size?

$$

<iframe height="300" style="width: 100%" scrolling="no" title="flexbox" src="https://codepen.io/3yya/embed/jOYbJJG?default-tab=css%2Cresult&editable=true&theme-id=light" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"></iframe>

flex-basis

定义了子项在主轴上的默认大小,当主轴是水平方向时 flex-basis 约等于 width , 当主轴是垂直方向时 flex-basis 约等于 height

flex

flex-growflex-shrinkflex-basis 的组合写法。默认值为 0 1 auto

align-self

定义单个子项的对齐方式,有以下取值:

  • auto:默认值,跟随容器 align-items 的定义。
  • flex-start:交叉轴开始处(cross start)对齐。
  • flex-end:交叉轴结束处(cross end)对齐。
  • center:交叉轴中部对齐。
  • baseline:交叉轴上基线对齐。 image

练习

  1. 试着让登录框实例水平垂直居中,查看演示效果。 $$answer
<!DOCTYPE html>
<html>
    <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" />
        <link rel="shortcut icon" type="image/x-icon" href="/logo-mini.png" />
        <title>登录框垂直居中</title>
        <style>
            :root {
                box-sizing: border-box;
            }
            *,
            *::before,
            *::after {
                box-sizing: inherit;
            }
            body {
                display: flex;
                justify-content: center;
                align-items: center;
                margin: 0;
                height: 100vh;
            }
            .box {
                text-align: center;
                width: 400px;
                border-radius: 14px;
                background-color: pink;
                border: 3px #65336e solid;
            }
            .title {
                font-size: 34px;
                font-weight: bold;
                color: white;
                border-radius: 11px 11px 0 0;
                padding: 20px 0;
                background-color: teal;
                margin-bottom: 20px;
            }
            .label {
                background: #eee;
                width: 70px;
                display: inline-block;
                border-radius: 3px 0 0 3px;
                height: 40px;
                line-height: 40px;
                vertical-align: middle;
                font-size: 14px;
                color: white;
                background-color: teal;
                font-weight: bold;
            }
            .username,
            .password {
                height: 40px;
                border: none;
                padding: 0;
                vertical-align: middle;
                border-radius: 0 3px 3px 0;
                padding: 0 10px;
            }
            .row,
            .login-btn {
                margin-bottom: 20px;
            }
            .login-btn {
                cursor: pointer;
                padding: 5px 30px;
                border: 3px #65336e solid;
                border-radius: 4px;
                background-color: #ffdb8a;
                color: #65336e;
                font-weight: bold;
                font-size: 22px;
            }
            .login-btn:hover {
                background-color: #fff0ce;
            }
            .login-btn:active {
                background-color: #fdcc59;
            }
            .username:focus,
            .password:focus {
                outline: none;
            }
        </style>
    </head>
    <body>
        <div class="box">
            <div class="title">登录页面</div>
            <div class="row">
                <label for="username" class="label">用户名</label
                ><input
                    id="username"
                    class="username"
                    type="text"
                    placeholder="请输入用户名"
                />
            </div>
            <div class="row">
                <label for="password" class="label">密码</label
                ><input
                    id="password"
                    class="password"
                    type="password"
                    placeholder="请输入密码"
                />
            </div>
            <button class="login-btn">登录</button>
        </div>
    </body>
</html>

$$

  1. 试着让导航栏实例两端对齐,查看演示效果。 $$answer
<!DOCTYPE html>
<html>
    <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" />
        <link rel="shortcut icon" type="image/x-icon" href="/logo-mini.png" />
        <title>导航栏两端对齐</title>

        <style>
            :root {
                box-sizing: border-box; /* 设置根元素的 box-sizing: border-box */
            }
            *,
            *:before,
            *:after {
                box-sizing: inherit; /* box-sizing 继承自父元素 */
            }

            body {
                margin: 0;
            }

            .navigator {
                height: 60px;
                box-shadow: 0 0 4px #999;

                padding: 0 40px;

                display: flex;
                justify-content: space-between;

                align-items: center;
            }

            .navigator a {
                text-decoration: none;
                color: inherit;
            }

            .brand {
                display: flex;
                align-items: center;
            }

            .logo {
                height: 40px;
            }

            .name {
                font-size: 20px;
            }

            .route {
                position: relative;
            }

            .route > a {
                padding: 10px 25px;
                border-radius: 4px;
                cursor: pointer;
            }
            .route:hover > a {
                background-color: #eee;
            }

            .route .container {
                padding-top: 15px;
                top: 30px;
                left: 0;
                display: none;
                position: absolute;
                font-size: 14px;
                /* background-color: red; */
            }
            .route:hover .container {
                display: block;
            }

            .route .container ul {
                list-style: none;
                margin: 0;
                padding: 0;
                box-shadow: 0 0 4px #999;
                background-color: white;
                border-radius: 4px;
            }

            .route .container li {
                cursor: pointer;
            }
            .route .container li:hover {
                background-color: #eee;
            }

            .route .container li a {
                display: inline-block;
                padding: 10px;
                min-width: 140px;
            }
        </style>
    </head>
    <body>
        <header class="navigator">
            <div class="brand">
                <img
                    class="logo"
                    src="https://3yya.com/logo-mini.png"
                    alt="logo"
                />
                <h3 class="name">三眼鸭编程</h3>
            </div>
            <div class="routes">
                <span class="route">
                    <a href="https://3yya.com/" target="_blank">首页</a>
                </span>
                <span class="route">
                    <a href="https://3yya.com/" target="_blank">教程</a>
                    <div class="container">
                        <ul>
                            <li>
                                <a
                                    href="https://3yya.com/course/2"
                                    target="_blank"
                                    >Python</a
                                >
                            </li>
                            <li>
                                <a
                                    href="https://3yya.com/course/3"
                                    target="_blank"
                                    >设计模式</a
                                >
                            </li>
                            <li>
                                <a
                                    href="https://3yya.com/course/9"
                                    target="_blank"
                                    >爬虫</a
                                >
                            </li>
                        </ul>
                    </div>
                </span>
                <span class="route">
                    <a href="https://3yya.com/courseware" target="_blank"
                        >教材</a
                    >
                    <div class="container">
                        <ul>
                            <li>
                                <a
                                    href="https://3yya.com/courseware/chapter/30"
                                    target="_blank"
                                    >前端课</a
                                >
                            </li>
                            <li>
                                <a
                                    href="https://3yya.com/courseware/chapter/32"
                                    target="_blank"
                                    >HTML</a
                                >
                            </li>
                            <li>
                                <a
                                    href="https://3yya.com/courseware/chapter/43"
                                    target="_blank"
                                    >CSS</a
                                >
                            </li>
                        </ul>
                    </div>
                </span>
            </div>
        </header>
    </body>
</html>

$$

  1. 试着写一个弹性伸缩的搜索框,查看演示效果。 $$answer
<!DOCTYPE html>
<html>
    <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" />
        <link rel="shortcut icon" type="image/x-icon" href="/logo-mini.png" />
        <title>导航栏两端对齐</title>

        <style>
            :root {
                box-sizing: border-box; /* 设置根元素的 box-sizing: border-box */
            }
            *,
            *:before,
            *:after {
                box-sizing: inherit; /* box-sizing 继承自父元素 */
            }

            body {
                margin: 0;
            }

            .navigator {
                height: 60px;
                text-align: center;
                line-height: 60px;
                /* border-bottom: 1px solid #eee; */
                box-shadow: 0 0 4px #999;

                padding: 0 20px;

                display: flex;
                justify-content: space-between;
                align-items: center;

                gap: 80px;
            }

            .brand {
                /* 作为容器的属性 */
                display: flex;
                align-items: center;

                /* 作为子项的属性 */
                /* 防止被压缩 */
                flex-shrink: 0;
            }

            .routes {
                /* 作为子项的属性 */
                /* 防止被压缩 */
                flex-shrink: 0;
            }

            .search {
                height: 40px;
                flex: 1;
                border-radius: 20px;
                padding: 20px;
                border: none;
                outline: none;
                background-color: #eee;
            }

            .navigator a {
                text-decoration: none;
                color: inherit;
            }

            .logo {
                height: 40px;
            }

            .name {
                font-size: 20px;
            }

            .route {
                position: relative;
                /* margin-right: 10px; */
            }

            .route > a {
                padding: 10px 25px;
                border-radius: 4px;
                cursor: pointer;
            }
            .route:hover > a {
                background-color: #eee;
            }

            .route .container {
                padding-top: 15px;
                top: 30px;
                left: 0;
                display: none;
                position: absolute;
                font-size: 14px;
                /* background-color: red; */
            }
            .route:hover .container {
                display: block;
            }

            .route .container ul {
                line-height: initial;
                text-align: initial;
                list-style: none;
                margin: 0;
                padding: 0;
                box-shadow: 0 0 4px #999;
                background-color: white;
                border-radius: 4px;
            }

            .route .container li {
                cursor: pointer;
            }
            .route .container li:hover {
                background-color: #eee;
            }

            .route .container li a {
                display: inline-block;
                padding: 10px;
                min-width: 140px;
            }
        </style>
    </head>
    <body>
        <header class="navigator">
            <div class="brand">
                <img
                    class="logo"
                    src="https://3yya.com/logo-mini.png"
                    alt="logo"
                />
                <h3 class="name">三眼鸭编程</h3>
            </div>
            <input
                class="search"
                type="text"
                placeholder="输入你想搜索的内容"
            />
            <div class="routes">
                <span class="route">
                    <a href="https://3yya.com/" target="_blank">首页</a>
                </span>
                <span class="route">
                    <a href="https://3yya.com/" target="_blank">教程</a>
                    <div class="container">
                        <ul>
                            <li>
                                <a
                                    href="https://3yya.com/course/2"
                                    target="_blank"
                                    >Python</a
                                >
                            </li>
                            <li>
                                <a
                                    href="https://3yya.com/course/3"
                                    target="_blank"
                                    >设计模式</a
                                >
                            </li>
                            <li>
                                <a
                                    href="https://3yya.com/course/9"
                                    target="_blank"
                                    >爬虫</a
                                >
                            </li>
                        </ul>
                    </div>
                </span>
                <span class="route">
                    <a href="https://3yya.com/courseware" target="_blank"
                        >教材</a
                    >
                    <div class="container">
                        <ul>
                            <li>
                                <a
                                    href="https://3yya.com/courseware/chapter/30"
                                    target="_blank"
                                    >前端课</a
                                >
                            </li>
                            <li>
                                <a
                                    href="https://3yya.com/courseware/chapter/32"
                                    target="_blank"
                                    >HTML</a
                                >
                            </li>
                            <li>
                                <a
                                    href="https://3yya.com/courseware/chapter/43"
                                    target="_blank"
                                    >CSS</a
                                >
                            </li>
                        </ul>
                    </div>
                </span>
            </div>
        </header>
    </body>
</html>

$$

  1. 试着写一个后台布局,查看演示效果。 $$answer
<!DOCTYPE html>
<html>
    <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" />
        <link rel="shortcut icon" type="image/x-icon" href="/logo-mini.png" />
        <title>管理后台</title>
        <style>
            :root {
                box-sizing: border-box; /* 设置根元素的 box-sizing: border-box */
            }
            *,
            *:before,
            *:after {
                box-sizing: inherit; /* box-sizing 继承自父元素 */
            }
            body {
                margin: 0;
            }
            .container {
                height: 100vh;
                display: flex;
                flex-direction: column;
            }
            .header {
                background-color: #2e313a;
                padding: 0 20px;
                height: 30px;

                color: white;
                font-size: 14px;
                font-weight: bold;

                display: flex;
                justify-content: space-between;
                align-items: center;
            }
            .name {
                color: yellow;
            }
            .content {
                display: flex;
                flex: 1;
            }
            .navigator {
                width: 200px;
                background-color: #393d49;
                flex-shrink: 0;
                overflow: auto;
            }
            .main {
                flex: 1;
            }
            .brand {
                color: #bbb;
                text-align: center;
                font-size: 48px;
                font-weight: bold;
            }
            .navigator ul {
                list-style: none;

                padding: 0;
                margin: 0;

                color: white;
                font-size: 15px;
            }
            .navigator li {
                padding: 20px;
                cursor: pointer;
            }
            .navigator li:hover {
                background-color: #2e313a;
            }
            .navigator .online {
                background-color: teal;
            }
        </style>
    </head>
    <body>
        <div class="container">
            <header class="header">
                <span>三眼鸭编程</span>
                <span>
                    <span>管理员:</span>
                    <span class="name">三眼鸭</span>
                </span>
            </header>
            <div class="content">
                <aside class="navigator">
                    <ul>
                        <li class="online">首页</li>
                        <li>帖子</li>
                        <li>用户</li>
                        <li>管理</li>
                    </ul>
                </aside>
                <main class="main">
                    <h1 class="brand">三眼鸭编程</h1>
                </main>
            </div>
        </div>
    </body>
</html>

$$