Flex 布局
Flex 是 Flexible Box 的缩写,意为"弹性布局",它旨在提供一种更有效的方式来布局、对齐和分配容器中项目之间的空间,即使这些项目的大小未知或是动态(因此称为 "flex")。
Flex 布局背后的主要思想是让容器能够改变其项目的宽度/高度(和顺序),以最好地填充可用空间(主要是为了适应各种显示设备和屏幕大小)。flex 容器扩展项目以填充可用空间,或收缩项目以防止溢出。
最重要的是,Flexbox 布局与常规布局(基于垂直的块和基于水平的内联)相比是方向无关的。虽然这些方法对页面很有效,但它们缺乏灵活性来支持大型或复杂的应用程序(尤其是在方向改变、调整大小、拉伸、收缩等方面)。
Flex 布局在2009年由 W3C 提出的。它在所有的浏览器都支持。
Flex 兼容情况注意:Flexbox 布局最适合应用程序的组件和小规模布局,而 Grid 布局则适用于大规模布局。我们将在下一篇讲解 Grid 布局。
以下内容参考 Flexbox30,图片截自 A Complete Guide to Flexbox
基础概念
为了使 Flexbox 正常工作,您需要设置父子关系。父级是 Flex 容器,其中的所有内容都是子级或 Flex 项。
Flex 容器仅环绕其直接子容器。因此,没有孙子或孙子孙辈的关系。只有父母↔️直系子女!只要存在父子关系,就可以建立 Flexbox。因此,孩子也可以成为其孩子的伸缩容器。但这将是一个单独的 flex 容器。而且它不会继承祖父母的 flex 属性。
这里有一篇关于不能将文本容器设置为 flexbox 容器 Never make your text container a flexbox container。
imgFlexbox 在2轴系统中运行:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴是您将伸缩项目如何放置在伸缩容器中的定义方向。确定横轴非常简单,它是在垂直于主轴的方向上进行的。
记住不要把他比作数学上的 x 和 y 轴。因为 x 轴并不总是主轴。这可能会让你出错。
在每个轴上都有一个起点和终点。如果在主轴上,则将起始位置称为 main start,将结束位置称为 main end。相同的概念适用于交叉轴。知道开始和结束很重要,因为您可以控制弹性项目的放置位置。
项目默认沿主轴排列。单个项目占据的主轴空间叫做 main size
,占据的交叉轴空间叫做 cross size
。
属性
父容器和子项目都有自己的一套属性。
父容器
flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
子项目
flex-grow
flex-shrink
flex-basis
flex
order
align-self
父容器
父容器flex 容器有2种类型:flex 将创建一个块级 flex 容器,inline-flex 将创建一个 inline 级 flex 容器。
.parent {
display: flex /* default */ | inline-flex;
}
很简单地解释,块元素占据了容器的整个宽度。它们看起来像构建块,其中每个构建块彼此堆叠。内联元素仅占用其所需的空间。因此,它们似乎排成一行,或者彼此并排。
flex-wrap
默认情况下,弹性项目将尝试使其自身收缩以适合一行,换句话说,不进行换行。但是,如果您希望 flex 项保持其大小并在容器中的多行中溢出,则可以使用 flex-wrap: warp;
。此属性将使容器中的弹性项目占用多行。
.parent {
flex-wrap: nowrap /* default */ | wrap | wrap-reverse;
}
flex-wrap
flex-wrap
允许 flex 项在单独的行上进行包装。但有了 align-content
,我们可以控制那些项目行在横轴上的对齐方式。由于这仅适用于包装的项目,所以如果只有一行 flex 项,则此属性不会有任何效果。
flex-flow
flex-flow
是 flex-direction
和 flex-wrap
的简写。默认值为 row nowrap。如果仅设置一个值,则未设置的属性将采用默认值。
.parent {
flex-flow: row nowrap /* default */ | <flex-direction> <flex-wrap> | <flex-direction> | <flex-wrap>;
}
flex-direction
定义主轴的属性。记住主轴可以是水平或垂直的。因此,如果我们希望主轴水平,则称为行。如果我们希望它是垂直的,那就叫做专栏。另外,请记住我们有一个主要的起点和终点。我们只需添加一个反向后缀即可将我们的“主要起点”设置为反向。
.parent {
flex-direction: row /* default */ | row-reverse | column | column-reverse;
}
flex-direction
justify-content
justify-content
设置沿主轴对齐的属性。align-items
设置沿横轴对齐的属性。记住横轴始终垂直于主轴。
.parent {
justify-content: flex-start /* default */ | flex-end | center | space-around | space-between | space-evenly;
}
justify-content
主轴也可以垂直放置。在这种情况下,将 flex-direction
设置为 column。
.parent {
flex-direction: column;
justify-content: flex-start /* default */ | flex-end | center | space-around | space-between | space-evenly;
}
align-items
.parent {
align-items: stretch /* default */ | flex-start | flex-end | center | baseline;
}
align-items
现在,让我们看一下如果交叉轴水平放置,则弹性项目如何对齐。换句话说,伸缩方向是列。
.parent {
flex-direction: column;
align-items: stretch /* default */ | flex-start | flex-end | center | baseline;
}
align-content
align-content
属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
.parent {
align-content: stretch /* default */ | flex-start | flex-end | center | space-between | space-around;
}
align-content
space-evenly 和 space-around
在 space-evenly
中,弹性项目之间的空白空间始终相等。
但是,在 space-around
上,只有内部项目之间的间距相等。第一项和最后一项将仅分配一半的间距。使它的视觉外观更加散布
子项目
子项目order
默认情况下,弹性项目的显示顺序与在代码中显示的顺序相同。但是,如果您要更改该怎么办?没问题!使用 order
属性更改商品的顺序。
.child {
order: 0 /* default */ | <number>;
}
order
flex-grow
Flexbox 非常适合响应式设计。flex-grow
属性允许我们的 flex 项在必要时增长。因此,如果我的容器中有多余的可用空间,我可以告诉某个特定项目按一定比例将其填满。
.child {
flex-grow: 0 /* default */ | <number>;
}
flex-grow
flex-shrink
如果有伸缩空间,flex-grow
将会扩展以填充额外的空间。相反 flex-shrink
当空间不足时将会控制 flex 项目缩小到适合的程度。请注意,数字越大,缩小幅度越大。
.child {
flex-shrink: 1 /* default */ | <number>;
}
你可以在 flex-grow-calculation 和 flex-shrink-calculation 查看浏览器如何帮我们自动处理 flex-grow
、flex-shrink
。
flex-basis
使用 flex-basis
属性,可以设置项目的初始大小。您可以将此属性视为 flex 项目的宽度。
因此,您的下一个问题可能是 width
和 flex-basis
之间的区别是什么。当然,您仍然可以使用 width
,它将仍然有效。
它起作用的原因是,如果未设置 flex-basis
,它将默认为 width
。因此,您的浏览器将始终尝试将 flex-basis
值用作大小指示器。如果找不到它,那就别无选择,只能使用您的 width
属性。不要让浏览器做额外的工作。以正确的 flex 方法进行操作,并使用flex-basis
。
.child {
flex-basis: auto /* default */ | <width>;
}
当一个项目具有 flex-basis
和 width
时,浏览器将始终使用 flex-basis
设置的值。但要注意,如果同时设置了 min-width
和 max-width
。在这些情况下,flex-basis
将丢失,并且不会用作宽度。
flex
flex 是上面所提到的 flex-grow
、flex-shrink
和 flex-basis
的简写形式。如果你足够了解它们的特性,请使用简写吧!!!
.child {
flex: 1 0 auto /* default */ |
<flex-grow> <flex-shrink> <flex-basis> |
<flex-grow> |
<flex-basis> |
<flex-grow> <flex-basis> |
<flex-grow> <flex-shrink>;
/* 相当于: */
flex-grow: 1;
flex-shrink: 0;
flex-basis: auto;
}
align-self
align-items
属性可以沿着横轴设置 flex 项。align-items
的问题是它强制所有 flex 项使用规则。
但是如果你想让他们中的一个打破规则,你可以使用 align-self
。此属性接受为 align-items
提供的所有相同值,因此您可以轻松脱离包装😎
.child-1 {
align-self: stretch /* default */ | flex-start | flex-end | center | baseline;
}
align-self
技巧
垂直水平居中元素
方式一
.container {
display: flex;
justify-content: center; /* horizontal */
align-items: center; /* vertical */
}
方式二
.container {
display: flex;
}
.container > div {
margin: auto;
}
水平垂直居中
对齐 Flexbox 子元素的另一种方法是使用自动页边距。尽管这不是 Flexbox 属性,但要意识到这一点仍然很重要,因为它与 Flexbox 有非常有趣的关系。Bonus: Aligning with Auto Margins
重新排序
.container > .top {
order: 1;
}
.container > .bottom {
order: 2;
}
截断文本
.parent {
display: flex;
align-items: center;
padding: 10px;
margin: 30px 0;
}
.child {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.child > h2 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.truncated {
flex: 1;
h2 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
移动布局
创建固定高度的顶栏和动态高度的内容区域。
.container {
display: flex;
flex-direction: column;
}
.container > .top {
flex: 0 0 60px;
}
.container > .content {
flex: 1 0 auto;
}
流式布局
自动用适当数量的盒子填充可用空间。
.container {
display: flex;
flex-wrap: wrap;
align-content: flex-start;
gap: 1rem;
}
.container > * {
flex: 1 1 10ch;
}
流式布局
响应导航栏
.nav {
display: flex;
flex-flow: row wrap;
justify-content: flex-end;
list-style: none;
margin: 0;
background: deepskyblue;
}
.nav a {
text-decoration: none;
display: block;
padding: 1em;
color: white;
}
.nav a:hover {
background: #1565C0;
}
@media all and (max-width: 800px) {
.nav {
justify-content: space-around;
}
}
@media all and (max-width: 600px) {
.nav {
flex-flow: column wrap;
padding: 0;
}
.nav a {
text-align: center;
padding: 10px;
border-top: 1px solid rgba(255, 255, 255,0.3);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.nav li:last-of-type a {
border-bottom: none;
}
}
类似于表
.container {
display: flex;
}
.container > .checkbox {
flex: 1 0 20px;
}
.container > .subject {
flex: 1 0 400px;
}
.container > .date {
flex: 1 0 120px;
}
这将创建宽度不同的列,但大小会根据具体情况而相应调整。
固定脚部
HTML 结构
<section>
<header></header>
<main></main>
<footer></footer>
</section>
方式一
section {
display: flex;
flex-direction: column;
height: 100vh;
}
main {
flex: 1;
}
方式二
section {
display: flex;
flex-direction: column;
}
footer {
margin-top: auto;
}
砌体布局
.masonry-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
max-height: 600px;
.masonry-brick {
margin: 0 .825rem .825rem 0;
border-radius: 1rem;
}
}
/* or */
.masonry-container {
display: flex;
flex-wrap: wrap;
.masonry-brick {
flex: 1 0 auto;
height: 150px;
margin: 0 .825rem .825rem 0;
border-radius: 1rem;
}
}
砌体布局
圣杯布局
html 结构
<div class="container">
<header class="header">Header</header>
<article class="main">lorem</article>
<aside class="aside aside-1">Aside 1</aside>
<aside class="aside aside-2">Aside 2</aside>
<footer class="footer">Footer</footer>
</div>
css
.container {
display: flex;
flex-flow: row wrap;
text-align: center;
}
.container > * {
padding: 10px;
flex: 1 100%;
}
.main {
text-align: left;
}
@media all and (min-width: 600px) {
.aside { flex: 1 0 0; }
}
@media all and (min-width: 800px) {
.main { flex: 3 0px; }
.aside-1 { order: 1; }
.main { order: 2; }
.aside-2 { order: 3; }
.footer { order: 4; }
}
双飞翼布局
双飞翼布局其实是根据圣杯布局演化出来的一种布局。
.container {
display: flex;
flex-flow: row nowrap;
justify-content: space-around;
height: 100%;
}
.left,
.right {
width: 200px;
flex-shrink: 1;
}
.main {
flex-grow: 1;
}
双飞翼布局
两列布局
.container {
display: flex;
}
.left {
width: 200px;
height: 100%;
}
.right {
flex: 1;
height: 100%;
}
两列布局