- 内容简介
- 译者序
- 前言
- 第 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 的力量了。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论