- 内容简介
- 译者序
- 前言
- 第 1 章 安装配置新项目
- 第 2 章 Flexbox 布局介绍
- 第 3 章 用 React Native 开发一个应用
- 第 4 章 在 React Native 中使用导航
- 第 5 章 动画和滑动菜单
- 第 6 章 用 React Native 绘制 Canvas
- 第 7 章 使用 React Native 播放音频
- 第 8 章 你的第一个自定义视图
- 第 9 章 Flux 介绍
- 第 10 章 处理复杂的应用程序状态
- 第 11 章 使用 Node 来实现服务端 API
- 第 12 章 在 React Native 中使用文件上传
- 第 13 章 理解 JavaScript Promise
- 第 14 章 fetch 简介
- 第 15 章 在 iOS 中使用 SQLite
- 第 16 章 集成 Google Admob
- 第 17 章 React Native 组件国际化
- 附录 A React.js 快速介绍
- 附录 B Objective-C Primer
- 附录 C webpack 入门
Flexbox 教程
本教程不会涵盖到 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 的力量了。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论