返回介绍

Flexbox 教程

发布于 2025-04-26 18:09:25 字数 13878 浏览 0 评论 0 收藏

本教程不会涵盖到 Flexbox 的所有知识点,所以如果你想要了解全部知识,我建议你去阅读官方文档。相反,本教程将使用 Flexbox 来解决一些常见的布局问题,并展示如何快速轻松地使用它们。这些布局模式都是响应式的,能够很好地展示 Flexbox 的易用性。以下是我们将要实践的案例:

1.一个普通的栅格系统

2.圣杯布局

3.带有可变宽度搜索框的流式导航条

4.两种不同的垂直对齐

下面就让我们来深入了解一下吧!

栅格系统

目前,栅格系统在页面的布局管理中占据了很重要的地位。默认盒模型的行为导致在布局中通常会使用 float 和 inline-block 等 hacks 方式来实现,这些方式都有很多人在使用。Flexbox 能让我们仅仅使用很少的几行 CSS 代码就轻松开发出一套功能强大、可扩展的栅格系统。让我们看看怎么做吧。

在传统的栅格系统中,我们必须用某种方式说明在一行中包含有多少个内容节点,然后给每个内容节点设置相应的宽度。通过 Flexbox,我们可以在一行中放任意数目的项目,而且这些项目的宽度可以根据容器宽度自动分配。换句话说,在 CSS 中,我们可以通过一些标记来达到目的,而不用关心一行中放置多少个内容节点,代码如下。

<div class="grid">
    <div class="grid_row">
        <div class="grid_item">1</div>
        <div class="grid_item">2</div>
    </div>
    <div class="grid_row">
        <div class="grid_item">1</div>
        <div class="grid_item">2</div>
        <div class="grid_item">3</div>
    </div>
    <div class="grid_row">
        <div class="grid_item">1</div>
        <div class="grid_item">2</div>
        <div class="grid_item">3</div>
        <div class="grid_item">4</div>
    </div>
</div>

现在让我们看看 CSS 代码。纯粹出于美观的考虑,我在其中使用了一些附加的样式属性(比如 border 和 padding),但是除了这些内容之外,我们所要使用到的样式属性非常简单,来看一下:

.grid {
    border: solid 1px #e7e7e7;
  }

.grid_row {
    display: flex;
  }

.grid_item {
    flex: 1;
    padding: 12px;
    border: solid 1px #e7e7e7;
}

这样我们就实现了一个栅格系统。.grid_row 定义了一个 flex 的容器,每一个.sub-item 的节点作为 flex 容器中的子元素。在.sub-item 中的 flex: 1 使得所有的项目等宽分布在容器中。现在你可以建立很多的栅格行,每行中的项目数量不限。它们会在容器中等宽分布,你不需要增加任何其他的 CSS 样式了。

那么如果想要得到一个列布局该怎么做呢?如果你想让栅格容器中的项目按列来分布,只要简单地在.grid-row 样式中声明 flex-direction:column;就可以实现。在这种情况下,我们只做了一点修改就创建了一个简单的快速响应布局,我们修改后的样式看起来像

这样:

<div class="grid">
    <div class="grid__row grid__row--sm">
        <div class="grid__item">1</div>
        <div class="grid__item">2</div>
        <div class="grid__item">3</div>
        <div class="grid__item">4</div>
    </div>
    <div class="grid__row grid__row--md">
        <div class="grid__item">1</div>
        <div class="grid__item">2</div>
        <div class="grid__item">3</div>
        <div class="grid__item">4</div>
        <div class="grid__item">5</div>
        <div class="grid__item">6</div>
        <div class="grid__item">7</div>
    </div>
    <div class="grid__row grid__row--lg">
        <div class="grid__item">1</div>
        <div class="grid__item">2</div>
        <div class="grid__item">3</div>
    </div>
</div>

我们修改后的 CSS 代码如下:

.grid {
    border: solid 1px #e7e7e7;
}

.grid__row {
    display: flex;
    flex-direction: column;
}

.grid__item {
    flex: 1;
    padding: 12px;
    border: solid 1px #e7e7e7;
}

@media all and ( min-width: 480px ) {
    .grid__row--sm {
        flex-direction: row;
    }
}

@media all and ( min-width: 720px ) {
    .grid__row--md {
        flex-direction: row;
    }
}

@media all and ( min-width: 960px ) {
    .grid__row--lg {
        flex-direction: row;
    }
}

瞧,一个简单的响应式栅格系统的 CSS 代码只有几行。这个系统的适应性非常强,你甚至可以嵌套栅格,而不必担心它的展现不够理想,如下页图所示。

<div class="grid">
  <div class="grid__row grid__row--sm">
    <div class="grid__item">
      <div class="grid">
        <div class="grid__row grid__row--lg">
          <div class="grid__item">Nested 1</div>
            ...
        </div>
      </div>
      </div>
      <div class="grid__item">2</div>
    </div>
    <div class="grid__row grid__row--md">
      <div class="grid__item">1</div>
          ...
    </div>
</div>

圣杯布局

圣杯布局在网页设计中非常著名,它在 Web 应用刚出现时就很出名,到今天圣杯布局依然扮演着重要角色,尤其是在内容丰富的网站中使用非常多。早在 2006 年,A List Apart 网站就已经使用这种方式来完美实现页面布局。它利用 float、margin 负值和最小宽度(min-width)来确保布局不相冲突。这种方式如果要满足现有响应式布局的需求,就需要用到大量的运算、浮动清除等一些特殊的手段。如果一个场景可能需要修改侧边栏的宽度,那你就不得不借助数学运算或者其他方式来实现。

Flexbox 布局能够有效地缓解这些让人头疼的问题,我们可以指定列布局或者行布局,也可以明确指定元素的分布顺序,就算不按照它们在页面中出现的顺序也可以。下面是一个典型的圣杯布局。

<body class="holy-grail">
    <header class="holy-grail__header"></header>
    <main class="holy-grail__body">
        <div class="holy-grail__content"></div>
        <div class="holy-grail__sidebar holy-grail__sidebar--first
            "></div>
        <div class="holy-grail__sidebar holy-grail__sidebar--second
            "></div>
    </main>
    <footer class="holy-grail__footer"></footer>
</body>

在我的 demo 中,圣杯布局是包含在一个页面文档中的,所以并没有上面出现的 body 标签或者 main 标签。我们不必关注这个,我们关心的是类名和部分标记,而不是元素本身的外观。特别是要注意用来修饰两个侧边栏的类,它们在标记中有细小的差别。让我们来仔细看看究竟发生了什么。

- 我们有一个父元素,类名为.holy-grail,在这个元素里面,有三个 flex 容器的子元素。这些子元素的类名分别是.holy-grail__header、holy-grail__body 及.holy-grail__footer。

- 这三个元素堆叠起来,占据了容器的所有宽度,所以容器就需要指定子元素的排列方式为列布局。

- 圣杯布局的 body 由.holy-grail__body 管理,它是一个 flex 子容器。它自己的子元素在较窄的屏幕中应该按照列布局,而在较宽的屏幕中应该按照行布局。

根据上面的分析,我们来建立自己的圣杯布局:

.holy-grail {
            display: flex;
            flex-direction: column;
        }

        .holy-grail__header,
        .holy-grail__footer {
            flex: 0 0 100%;
        }

        .holy-grail__body {
            display: flex;
        }

        .holy-grail__sidebar {
          /* 窄屏下不显示

 */
        }

        .holy-grail__sidebar--first {
              order: 1;
        }

        .holy-grail__sidebar--second {
              order: 3;
        }

        .holy-grail__content {
              order: 2;
        }

        @media all and ( min-width: 720px ) {
              .holy-grail__body {
                  flex-direction: row;
              }
              .holy-grail__sidebar {
                  flex: 0 0 180px;
              }
              .holy-grail__content {
                  flex: 1;
              }
        }

        @media all and ( min-width: 960px ) {

              .holy-grail__sidebar {
                  flex: 0 0 240px;
              }

        }

效果如下图。这真的不能再简单了。我之前提到过断点,在这个布局中,在初始的状态(窄屏幕)下,我们设置了两个 flex 容器。在第一个断点的情况下,我们修改了 body 的 flex 方向,以行布局显示,使用 flex 属性的简写方式设置侧边栏宽度为 180px。这种简写的方式能让我们同时设置 flex-grow、flex-shrink 属性,以及 flex-basis。内容使用 flex: 1 来填充可用的空间。使用 order 属性对项目进行排序也是非常简单的。除了那些为了美观而增加的属性,其他真没什么了。之前说过,Flexbox 布局的每一列默认宽度都相等。

带有可变宽度搜索框的流式导航条

下一个例子很有意思,我们将构造一个全宽度、流式布局的导航。这个导航包含一个搜索框,在获取到焦点的时候会平滑过渡到更大的宽度。通过 Flexbox 的力量,我们能够给导航增加任意数量的导航项目而不用修改 CSS,我将会添加一些额外的类名来实现希望的效果。此外,还将使用一个按钮来进行效果的切换。代码如下:

<nav class="flexy-nav">
    <button id="flexy-nav__toggle" class="flexy-nav__toggle">Toggle
        Nav</button>
    <ul id="flexy-nav__items" class="flexy-nav__items">
        <li class="flexy-nav__item"><a href="#" class="flexy-
            nav__link">Item 1</a></li>
        <li class="flexy-nav__item"><a href="#" class="flexy-
            nav__link">Item 2</a></li>
        <li class="flexy-nav__item"><a href="#" class="flexy-
            nav__link">Item 3</a></li>
        <li class="flexy-nav__item"><a href="#" class="flexy-
            nav__link">Item 4</a></li>
    </ul>
    <form action="" class="flexy-nav__form">
        <input class="flexy-nav__search" type="text" placeholder="
            Type search terms and hit enter...">
  </form>
</nav>

来分析一下上述代码的结构。我们有一个 flex 的主容器,由.flexy-nav 类来控制其样式。有一个按钮(button)作为一个开关,主导航的条目是一个无序列表的形式,一个 form 表单中放置搜索框。在窄屏的情况下,我们希望三个部分以列的形式显示,同时每个导航条目本身也是列分布显示。在宽屏的情况下,我们想要隐藏切换按钮,让无序列表成为一个 flex 容器,使列表项目展现在一行中,给 form 表单一个固定宽度。列表的项目将会在剩余的空间中均匀分布。当 form 表单中的 input 框获取焦点的时候,我们希望看到它平滑地过渡到更宽,所有的项目平滑地收缩。

下面是 CSS 实现代码:

input,
button {
    font: inherit;
    border-radius: none;
    box-shadow: none;
    appearance: none;
}

button {
    cursor: pointer;
}

    /* nav container */
.flexy-nav {
    display: flex;
    flex-direction: column;
}

    /* nav links */
.flexy-nav__items {
    display: none;
    flex: 1;
    flex-direction: column;
    list-style: none;
    margin: 0 0 4px 0;
    padding: 4px;
    text-align: center;
}

.flexy-nav__items--visible {
    display: flex;
}

.flexy-nav__item {
    background-color: #f1f1f1;
    border-bottom: solid 1px #e7e7e7;
}
.flexy-nav__item:last-child {
        border-bottom: 0;
}
.flexy-nav__link {
    padding: 8px;
    display: block;
}
/* nav toggle */
.flexy-nav__toggle {
    margin: 0 0 4px 0;
    padding: 4px;
    color: #fff;
    background-color: #f07850;
    border: none;
}
.flexy-nav__toggle:hover,
.flexy-nav__toggle:focus {
    outline: none;
    background-color: #c93f11;
}
/* nav form */
.flexy-nav__form {
    height: 48px;
}
.flexy-nav__search {
    display: block;
    margin: 0;
    padding: 0 4px;
    width: 100%;
    height: 48px;
    color: #6d6d6d;
    background-color: #fff;
    border: solid 2px #e7e7e7;
}
.flexy-nav__search:focus {
    outline: none;
    border: solid 2px #6d6d6d;
}
/* media queries */
@media all and (min-width: 768px) {
    .flexy-nav {
        flex-direction: row;
    }
    .flexy-nav__items {
        display: flex;
        flex-direction: row;
        margin: 0;
        padding: 0;
        height: 48px;
    }
    .flexy-nav__item {
        flex: 1;
        margin-right: 4px;
        border-bottom: none;
    }
    .flexy-nav__link {
        padding: 0;
        line-height: 48px;
    }
    .flexy-nav__toggle {
        display: none;
    }
    .flexy-nav__form {
        flex: none;
    }
    .flexy-nav__search {
        width: 240px;
        transition: width 0.3s;
    }
    .flexy-nav__search:focus {
        width: 360px;
    }
}

按照我们的设想,这里有一段 JavaScript 代码,用来在较窄的屏幕中显示和隐藏导航。

(function() {
    var toggle = document.querySelector("#flexy-nav__toggle");
    var nav = document.querySelector("#flexy-nav__items");
    toggle.addEventListener("click", function(e) {
        e.preventDefault();
        nav.classList.contains("flexy-nav__items--visible") ?
            nav.classList.remove("flexy-nav__items--visible") :
            nav.classList.add("flexy-nav__items--visible");
    });
})();

就这么简单。我们创造了一个整洁的、可扩展的导航,并包含一个整洁的搜索框。在添加和删除链接或改变搜索框的尺寸时,一点都不影响其他的功能。嗯,这就是 Flexbox 的乐趣。

垂直居中

我们必须要面对一个问题,就是在传统的 CSS 中,垂直对齐的实现非常糟糕。有时候给节点设置 inline-block 能够解决这个问题,也有人使用绝对定位的 hack 来实现,还有人在使用很过时的 table 布局(在标签语义化的今天,这是不符合要求的)。所有这些提到的方式在实现垂直对齐时其实都有些怪异,而且都需要很多额外的开销才能够运作起来。

Flexbox 能够轻松地处理好这个问题。我们来看两个包含对齐问题的例子。

- 第一个例子,左侧是用户头像,右侧是用户的名字和一些信息。我们将使用 Flexbox 来使得用户头像在区域中垂直居中。

- 第二个例子,在一个宽度固定、高度可变的容器中,如何实现元素始终处于容器中心(水平和垂直方向都居中)。

我们先来处理第一个例子。我们需要将一个用户头像放到左边,一些描述放到右边。不管右边描述文字的长短,我们都希望用户的头像能够保持在垂直中心的位置,如下图。下面的代码是节点标记。

<div class="user">
    <div class="user__avatar"></div>
    <div class="user__description">
        <h2 class="user__username">John Doe</h2>
        <p class="user__excerpt">I'm John Doe...</p>
    </div>
</div>
<div class="user">
    <div class="user__avatar"></div>
    <div class="user__description">
        <h2 class="user__username">Harry Potter</h2>
        <p class="user__excerpt">I'm Harry Potter...with a really
            long description...</p>
    </div>
</div>

在深入分析 CSS 之前,提醒一点需要注意的,在这个例子中,我们将会使用一个之前没有讲过的 CSS 属性,这个属性就是 align-items,它能够让 flex 项目垂直于 flex 基准线方向上队列显示。

换句话说,如果 flex 基准线沿着水平方向,我们能够让每个项目基于这个水平线排列。在我们的例子中,我们想要让项目中心对齐,所以我们只要设置 align-items: center 就可以了,下面是 CSS 代码:

.user {
    display: flex;
    align-items: center;
}
.user:last-child {
    margin-bottom: 0;
}

.user__avatar {
    flex: 0 0 96 px;
    width: 96 px;
    height: 96 px;
    background-color: #e7e7e7;
}
.user__description {
    flex: 1;
    margin-left: 24 px;
    padding: 12 px;
    border: solid 1 px# e7e7e7;
}

就这么简单,你可以依照自己的喜好来设计文字的样子,你可以把描述文本写得尽可能长一些,也可以修改用户头像的尺寸,试试这个例子,你就能看到效果了。

我们继续来看垂直对齐的第二个例子。让我们想象一下,在所有的节点标记中最上面的是 banner,这个 banner 中有一些标题文本。在小屏幕中,banner 的高度是 180px,它将通过设置的两个断点将高度变化为 480px。每次变化后,我们都希望标题文本仍处在 banner 的中心,无论是水平方向还是垂直方向。下面是节点标记:

<div class="banner">
    <div class="banner__content">
        <h2 class="banner__title">Symmetrical Perfection</h2>
        <span class="banner__sub">A beautiful sight, achieved with
            flexbox.</span>
    </div>
</div>

这次我们将会使用 justify-content 属性。这个属性的作用是定义项目周围沿着 flex 基准线的空间如何显示。下面是 CSS 代码:

.banner {
    display: flex;
    align-items: center;
    justify-content: space-around;
    height: 180px;
    background-color: #e7e7e7;
}

.banner__content {
    text-align: center;
}

.banner__title,
.banner__sub {
    margin: 0;
    padding: 0;
    line-height: 1.5;
}
@media all and ( min-width: 480px ) {
    .banner {
        height: 240px;
    }
}

@media all and ( min-width: 768px ) {
    .banner {
        height: 360px;
    }
}

@media all and ( min-width: 960px ) {
    .banner {
        height: 480px;
    }
}

无论 banner 的高度是多少,内容总是会保持在水平和垂直方向的中心位置,这就是 Flexbox 的力量了。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。