本文篇幅较长,如果需要的话,你可以在这里下载文章后离线阅读。
理解 Flexbox 最好的方式是什么?学好基础,再大量练习。这正是我们要在这篇文章中做的事情。
要注意的几点
- 这篇文章预设你是一名中级开发者,并且对 Flexbox 有点了解,不过......
- 如果你对 CSS 有些了解,完全不知道 Flexbox,我写了一篇综合指南(免费文章,阅读时间约为 46 分钟)。
- 如果你对 CSS 掌握得不是很好,我推荐你阅读 CSS 全面(实用)指南 (74 课时的付费课程)。
- 你不需要遵照这里列出的示例顺序。
- Flexbox 只是一种布局的技巧,实际项目中涉及到的东西除了布局还有很多。
- 当你看到例如
div.ohans
的例子,这代表类名是ohans
的 div
例1: 如何用 Flexbox 制作一个影片集
使用 Flexbox 实现横向纵向排列比大多数人想象的要简单。
例如一个如下的简单标识文本:
<main class="gallery"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"></main>
main.gallery
里有十张图片。
假定 main.gallery
覆盖整个可见屏幕。
.gallery { min-height: 100vh}
有关图片的快速标记
图片默认是一个 inline-block 元素,有宽高,通常排列在同一行(除了图片尺寸有限定,一行排不下的情况)。
起始点
把所有图片放在一起,上面的标识文本显示效果如下:
现在,看下 Flexbox 的效果:
.gallery { display: flex }
现在,图片的默认属性已经发生改变。它们从 inline-block
元素变成了 flex-items.
由于 .gallery
里的 Flexbox 布局,里面的图片会被压缩排列在一行内,而且它们会被纵向拉伸成这样:
这就是由于 Flexbox 布局的默认展示方式:
1. 将所有的子元素压在一行内,不换行。
这并不适用于图片库,因此我们可以这样改变:
.gallery { flex-wrap: wrap}
这样所有的元素会在适当的位置换行成多行排列。
2. 现在图片有换行,但是仍然被纵向拉伸。我们当然不想要这样变形的布局。
stretch
显示是因为 flex
里默认的 align-items
值。
align-items: stretch
我们可以改成这样:
.gallery { ... align-items: flex-start}
这样图片不会拉伸,而是保持它们默认的宽和高。
如下所示,它们会在纵向保持首部对齐。
现在我们就有了使用 Flexbox 的强大图片集。
使用 Flexbox 的优点
此刻 Flexbox 似乎没展现出什么优势,图片还是像使用 Flexbox 之前一样。
除了能得到一个免费的响应式图片集外,使用 Flexbox 的另一个优势就是它的对齐选项。
还记得 flex 容器 .gallery
设定的样式 flex-direction: row
justify-content: flex-start
和 align-items: flex-start.
如下所示,改变默认值,我们就可以立马改变图片库的布局。
.gallery { ... justify-content:center;}
如上所示,这会让图片水平居中。
.gallery { ... justify-content:center; align-items: center;}
再进一步,我们可以让图片完美居中对齐(无论是水平还是垂直)
如上所示,这可以让图片在 .gallery
内水平和垂直都居中。
你可以通过 Flexbox 的布局方式随意选择你想要的对齐选项。
也可以在 CodePen查看 Flexbox 图片库的实时布局效果。
例 2:如何通过 Flexbox 布局卡片
卡片在网上很流行,无论是Google, Twitter 还是 Pinterest,每个网站都在使用卡片。
卡片是一种在弹性容器内组合相关信息的页面设计方式,视觉上很像一种玩的卡片。
有很多使用卡片的优秀案例,其中一个常用的就是臭名昭著的价格表。
让我们来建一个。
标识文本
我们给每个卡片设定一个如下的标识:
<section class="card"> <header> </header>
<ul> <li></li> <li></li> <li></li> </ul> <button></button></section>
这里有至少 3 个卡片,我们把这些卡片包在 div.cards
里
<div class="cards"></div>
现在已经有了一个父元素。在这个例子中,父元素充满整个视图。
.cards { min-height: 100vh}
建立 Flexbox 布局
下面的代码块新建了一个在 .cards
里面的 Flexbox 布局样式。
.cards { display: flex; flex-wrap: wrap}
如果你还记得上一个例子, flex-wrap
可以让 flex-items
元素换行。
由于子元素排列需要更大的宽度,所以子元素不能在父元素内排列时就会换行。
接下来我们给 .card
元素一个初始宽度。
使用 Flexbox 如下布局:
.card { flex: 0 0 250px}
这个样式将 flex-grow
和 flex-shrink
的值设为 0, flex-basis
值为 250px
。
这时,卡片会在页面的起始处对齐,并且竖向排列。
这有时可能满足你的使用需求,但大部分情况下,都不行。
Flex 容器的默认值
上面的布局效果是由于 flex 容器的默认布局设置。
卡片在页面内靠左上角对齐,因为 justify-content
的值默认为 flex-start
。
同时,卡片垂直拉伸充满整个父元素的高度,因为 align-items
的默认值是 stretch
。
改变默认值
我们可以通过改变 Flexbox 提供的默认值来达到更好的效果。
看下面几个例子:
align-items: flex-start; justify-content: center
align-items: flex-end; justify-content: center
align-items: center; justify-content: center
你可以在CodePen看最终的效果。
例 3:如何使用 Flexbox 创建网格布局
在这个例子中,我们要探讨整体的 CSS 框架概念,这是很重要的一点。
什么是网格布局?
网格是用来构建内容的一系列水平垂直相交引导线。
如果你对 Bootstrap 这样的 CSS 框架比较熟悉,那你之前一定使用过网格布局。
你所掌握的内容可能不一样,但这个例子会涵盖不同的网格布局类型。
我们先来看第一种,基本网格布局
基本网格布局
这些网格有以下特点:
- 网格单元格平均布局并充满整行。
- 单元格高度一致。
使用 Flexbox 很容易实现这个效果,看下面这个标识文本:
<div class="row"> <div class="row_cell">1</div></div>
每个 .row
都是自己的 flex 容器。
.row
里的每个元素也就是 flex 元素,所有的 flex 元素都平均分布在一行中。
根据设计,无论有 3 个子元素
<div class="row"> <div class="row_cell">1/3</div> <div class="row_cell">1/3</div> <div class="row_cell">1/3</div></div>
6 个子元素
<div class="row"> <div class="row_cell">1/6</div> <div class="row_cell">1/6</div> <div class="row_cell">1/6</div> <div class="row_cell">1/6</div> <div class="row_cell">1/6</div> <div class="row_cell">1/6</div></div>
或是 12 个子元素,都是没影响的
<div class="row"> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div></div>
解决方案
达到这个效果只需要两步:
- 新建一个 Flexbox 布局文本:
.row { display: flex;}
2. 扩大每个 flex-item
元素,让它们以相同比例均匀的布满整行:
.row_cell { flex: 1}
就是这样
方案解释
flex: 1
flex
是 flex-grow
、 flex-shrink
和 flex-basis
三个不同 Flexbox 属性的缩写。
flex: 1
只有 1
的值,这个值代表的是flex-grow
属性。
而 flex-shrink
和 flex-basis
则分别设置为 1
和 0
。
flex: 1 === flex: 1 1 0
有确定大小的网格元素
有时候你需要的效果并不是同样大小的水平网格布局。
你可能想要一个元素是其他的两倍,或者几分之一。
实现方式很简单。
对于这些有确定大小的网格元素,只需要加一个这样的修饰符类:
.row_cell--2 { flex: 2}
加上这个类,可以看到第一个 div
子元素代码如下:
<div class="row"> <div class="row_cell row_cell--2">2x</div> <div class="row_cell">1/3</div> <div class="row_cell">1/3</div></div>
加上 .row__cell--2
类名的元素会是其他默认元素的两倍大小。
一个占可用空间 3 倍的元素:
.row_cell--3 {
flex: 3
}
有确定对齐方式的网格元素
多亏了 Flexbox 布局,我们不需要给每个元素设置特定的对齐值。你可以给任何一个元素设定不同的对齐方式。
通过下面的修饰符类,可以达到这样的效果:
.row_cell--top { align-self: flex-start}
这可以让特定的元素在 row
内靠顶部对齐。
你一定有在标识文本中给特定元素加上这个类。看文本中第一个 div
子元素:
<div class="row"> <div class="row_cell row_cell--top"></div> <div class="row_cell"></div> <div class="row_cell"></div></div>
下面是其他可选的对齐方式:
.row_cell--bottom { align-self: flex-end}
.row_cell--center { align-self: center}
行内对齐
像特定的元素可以对齐一样,行内子元素也可以整体对齐。
可以使用下面的修饰符类达到这样的效果:
.row--top { align-items: flex-start}
需要注意的一个重点是,修饰符类 .row--top
一定要被加在 row
或是父元素 flex-container
上。
<div class="row row--top"> <div class="row_cell"></div> <div class="row_cell"></div> <div class="row_cell"></div></div>
其他的对齐选项见下:
.row--center { align-items: center}
.row--bottom { align-items: flex-end}
嵌套网格
只需要简单的设置,rows(行元素)就可以嵌套布局。
你可以在 created here查看最终的布局效果。
更多网格布局
当你可以用 Flexbox 垂直网格甚至更复杂的参数实现好看的网格构造时,就可以把这个很好的工具用于工作。学习,掌握然后使用 CSS 网格布局,这是 CSS 网格布局的最终解决方案。
例 4:如何使用 Flexbox 构建网站布局
社区通常不建议整个网站布局都使用 Flexbox。
虽然我赞同这个观点,但是我也认为在特定的情况下你可以不用考虑这么多。
我能给到最重要的一点建议是:
在你需要的时候使用 Flexbox 布局
我会在下面的例子中解释这点。
圣杯布局
有什么网站布局方式比“圣杯布局”更经典呢?
有两种 Flexbox 方式可以实现这种布局。
第一种是用 Flexbox 来实现布局。把 header
, footer
, nav
, article
和 aside
都放在一个 flex-container
容器里。
我们开始吧。
标识语言
看下下面这个基本的标识语言:
<body> <header>Header</header> <main> <article>Article</article> <nav>Nav</nav> <aside>Aside</aside> </main> <footer>Footer</footer></body>
其中,圣杯布局遵循了一个特殊的规则,这个规则启发了上面的标识语言:
中间的那列 article
应该在 nav
和 aside
两个侧边栏之前显示出来。
建立一个 Flexbox 格式文本
body { display: flex}
因为子元素应该从顶部到底部布局,所以我们要改变 Flexbox 的默认方向。
body { ... flex-direction: column}
1. header
和 footer
要有固定的宽度
header,footer { width: 20vh /*可以使用像素单位,例如200px*/}
2.main
要填满 flex-container
中剩下的部分。
main { flex: 1}
你一定没忘记, flex: 1
代表 flex-grow: 1
, flex-shrink: 1
和 flex-basis: 0
。
此刻,我们要开始考虑 main
中的 article
, nav
和 aside
三个部分。
把 main
设成一个 flex-container
:
main { display: flex}
给 nav
和 aside
以固定的宽度:
nav,aside { width: 20vw}
然后确保 article
填满剩下的可用空间:
article { flex: 1}
现在还需要做一件事。
把 flex-items
重新排序这样 nav
会展示在第一位:
nav { order: -1}
最终效果 https://codepen.io/ohansemmanuel/full/brzJZz/
order
属性用来重新排序 flex-items
的位置。
容器中所有 flex-items
都会以 增大的 order
值排列, flex-item
中 order
值最小的会排列在最前面。
所有的 flex-items
元素默认 order
值都是 0
。
圣杯布局 (另一种布局方式)
之前的方式是把 flex-container
作为一个整体的容器。这个布局非常依赖 Flexbox。
我们来了解一种更为“理智”的方法。首先再来看下最终要达到的效果:
header
和 footer
可以被当做块状元素。 在没有任何干预的情况下,它们会在从顶部到底部,填满父级元素。
<body> <header>Header</header> <main> <article>Article</article> <nav>Nav</nav> <aside>Aside</aside> </main> <footer>Footer</footer></body>
使用这种方法,唯一需要作为 flex-container
的就是 main
元素。
使用这个方法有个缺点就是你要自己计算 main
的高度。 main
应该填满除 header
和 footer.
外的空间。
main { height: calc(100vh - 40vh);}
上面的代码块使用 CSS 中的 calc
来计算 main.
的高度。
不管怎样, main
的高度都要等于 calc(100vh — 头部的高度 — 页脚的高度 ).
在之前的解决方案中, header
和 footer
都有一个固定的高度,接下来再通过同样的方法计算 main
的高度。
你可以在 actual results here 中查看最终效果。
两列网页布局
两列布局很常见,这也可以用 Flexbox 轻松实现。
看下以下标识文本:
<body> <aside>sidebar</aside> <main>main</main></body>
先建一个 Flexbox 格式文本:
body { display: flex;}
给 aside
一个固定的宽度:
aside { width: 20vw}
最后,确保 main
填满剩下的可用空间:
main { flex: 1}
这样就差不多可以了。
例5:使用 Flexbox 布局媒体对象
媒体对象随处可见。从 tweets 到 Facebook 上的发贴, 大部分页面设计似乎都会选择媒体对象。
Tweet 和 Facebook 上的发帖示例
看下下面这个标识文本:
<div class="media"> <img class="media-object" src="/pic.jpg"> <div class="media-body"> <h3 class="media-heading"> Header </h3> <p></p> </div></div>
你应该已经猜到了, .media
会使用 Flexbox 布局:
.media { display: flex}
container
中的 flex-items
默认是在 flex-container
中垂直拉伸,填满可用高度。
确保 .media-body
填满剩下的可用空间:
.media-body { flex: 1}
我们来调整下拉伸的盒子模型。
.media { ... align-items: flex-start}
弹性项目在媒体对象中从起点对齐。现在图片保持默认大小,没有变形拉伸:)
就是这样。
画报媒体对象
画报媒体对象是图片在媒体对象的另一边(右边)
创建画报媒体对象不需要改变 html
元素的顺序。
只需要让弹性项目像这样重新排序:
.media-object { order: 1}
这样图片就会排列在 .media-body
和 media-heading
之后。
媒体对象的嵌套
你甚至可以不改变已有的 CSS 样式来继续用嵌套布局媒体对象。
<div class="media"> <img class="media-object" src="/pic.jpg"> <div class="media-body"> <h3 class="media-heading"> Header </h3> <p></p> <!--nested--> <div class="media"> <img class="media-object" src="/pic.jpg"> <div class="media-body"> <h3 class="media-heading"> Header </h3> <p></p> </div> </div><!--end nested--> </div> </div>
可以了!
媒体对象在其中嵌套布局
字符码媒体对象
我们不用只拘泥于图片。
在不改变已经写好的 CSS 样式情况下,你可以用字符码来代替图片。
<div class="media"> <div class="media-object">?</div> <div class="media-body"> <h3 class="media-heading"> Header </h3> <p></p> </div></div>
我在那里放了一个 emoji 表情。
带有 emoji 表情的媒体对象
上面用一个包含适当表情的编码来代替 img
。你可以在这里获取更多的emoji表情。
HTML实体媒体对象
你也可以使用如下的 html实体 。
<div class="media"> <div class="media-object">☎</div> <div class="media-body"> <h3 class="media-heading"> Header </h3> <p></p> </div></div>
这里使用的html实体是 ☎
,效果如下:
html实体, ☎
你可以在 CodePen查看这些例子的效果。
例 6:如何使用Flexbox建立表单元素
现在很难找到没有一两个表单的网站了。
看下面这段标识文本:
<form class="form"> <input class="form__field"> <button class="form__item">…</button></form><form class="form"> <span class="form__item">…</span> <input class="form__field"></form><form class="form"> <span class="form__item">…</span> <input class="form__field"> <button class="form__item">…</button></form>
这个例子展示了输入框与按钮或是文字的结合,我们仍可以用 Flexbox 轻松解决。
新建一个 Flexbox 格式文本:
.form { display: flex}
确保输入框填满可用空间:
.form__field { flex: 1}
最后,你可以按照你喜欢的方式在前后放入文字或者按钮。
.form__item { ... }
你可以在 CodePen里看到这个例子的完整效果。
例 7:如何使用 Flexbox 来创建一个手机 App 布局
在这个例子中,我会带你一起来打造一个如下的手机应用布局:
我们将通过 Flexbox 建立的手机应用布局
不过这个例子有点不同。
我会解释用代码建立手机布局的过程,你可以尝试完成。
这是一个让你 熟练 的方式。
第一步
剥离出 iPhone 的页面布局,我们得到下面这个:
骨架屏布局
第二步
将主体部分定义成一个 flex-container
将格式化文本建立成一个弹性容器
第三步
flex-container
默认的 flex-direction
属性是 row
。在这个例子中,我们要把它变成 column
。
改变 3 个子元素也就是 flex-items
的默认布局方向
第四步
给元素 1 和元素 3 一个固定的高度 height: 50px.
第五步
元素 2 要有一个填满可用空间的高度。使用flex-grow
或是简写的 flex
写法 flex: 1.
。
第六步
最后,像之前的例子一样,把每个块状元素当成一个媒体对象。
把内容块当成媒体对象
按照上面的六个步骤可以成功建立一个手机应用布局。
想要更专业?
免费下载我的 CSS 网格布局参考手册,还可以免费获得两节优质的响应式 Flexbox 课程!
点击免费获得免费的 CSS 网格布局手册 + 两节优质的课程!
原文:The Ultimate Guide to Flexbox — Learning Through Examples,作者:Emmanuel Ohans