如何使用 Flexbox 构建纯 CSS 智能布局
已发表: 2022-03-11灵活框,或简称 Flexbox,是 2009 年引入的 CSS 中的一组属性,用于提供一种新的、卓越的布局系统。 Flexbox 模块被标识为第三版 CSS (CSS3) 的一部分。
您可能已经在使用 CSS3 中的许多新属性,例如box-shadow
、 border-radius
、背景渐变等。 然而,Flexbox 尚未得到应有的广泛采用。 这可能是因为它多年来遭受的所有重大变化,或者因为它仅在 Internet Explorer 10 中得到部分支持,或者仅仅是因为 Flexbox 是一个完整的生态系统,而以前的范式主要基于单一的、随时可用的去属性。
它非常强大,并提供了广泛的选项来实现以前只能梦想的布局。
本文将引导您了解 Flexbox 的基础知识,以及如何使用它来实现一些非常酷的布局,否则这些布局需要复杂的 CSS hack 甚至 JavaScript。
为什么要使用 Flexbox?
默认情况下,HTML 块级元素是堆叠的,所以如果你想将它们排成一行,你需要依赖像float
这样的 CSS 属性,或者使用 table-ish 或 inline-block 设置来操作display
属性。
如果您选择使用float
(左或右),您必须在某个时候清除包装以将其推送到最后一个浮动元素,否则它们将溢出后面的任何内容。 但是,使用浮动,您只能水平组织元素。
或者,或者另外,您可以操纵display
属性以尝试实现您想要的布局! 但这通常让人觉得充其量是杂乱无章的,更不用说乏味了,而且通常会导致相当脆弱的布局,不一定会在浏览器中一致地呈现。 如果您针对不同尺寸的多个设备,这种方法尤其无效——如今几乎总是如此。
进入弹性盒!
通过将简单规则应用于父元素,您可以轻松控制其所有子元素的布局行为。
使用 Flexbox,您可以:
- 反转 Flexbox 父级中元素的顺序。
- 将子元素包装在列中(列数可能因子元素和父元素的高度而异)。
- 指定视口大小更改时元素增长或缩小的速率。
- 控制元素是否可收缩,而不管指定的宽度单位类型(相对或绝对)。
- 使用 CSS 更改元素的顺序(将其与媒体查询结合使用,您会发现流程中的无限可能)。
- 生成元素的复杂分布,使其与周围的空间或之间的空间等距。
- 生成流动不同的“叛徒”元素(每个人都在左边,但在右边,顶部/底部......这是你的电话)。
- 而且,最重要的是,永远避免使用 clear-fix hack!
我知道 Flexbox 一开始可能很难。 我认为学习十个不相关的 CSS 属性比学习五个相互依赖的 CSS 属性更容易。 但是,凭借您当前的 CSS 技能,以及本文的一些帮助,您将进入一个新的 CSS 世界。
Flexbox 基础知识
展示
display
是 CSS 中最基本的属性之一,在 Flexbox 的上下文中非常重要,因为它用于定义 flex 包装器。
有两种可能的 flex 包装器值: flex
和inline-flex
。
两者的区别在于display: flex
包装器的作用类似于块元素,而display: inline-flex
包装器的作用类似于 inline-block。 此外,如果没有足够的空间容纳子元素,则inline-flex
元素会增长。 但除了这些差异之外,两者的行为是相同的。
试试下面的示例代码,当 inline-flex 处于活动状态时减小视口宽度,然后……滚动。
请参阅 CodePen 上 DD (@Diegue) 的 Pen Flexbox @Toptal - Parent - `display` 属性。
.wrapper { display: flex || inline-flex; }
弯曲方向
现在您已经看到了第一个示例,您可以推断默认行为是简单地创建一行元素。 但还有更多:
- 行(默认):从左到右排列元素(但如果设置了 RTL,它将向后排列)。
- row-reverse:反转行配置中元素的顺序
- column:从上到下排列元素
- column-reverse:反转列配置中元素的顺序
提示:
column
和column-reverse
值可用于交换轴,因此影响水平轴的属性将影响垂直轴。
请参阅 CodePen 上 DD (@Diegue) 的 Pen Flexbox @Toptal - Parent - `flex-direction` 属性。
.wrapper { flex-direction: row || row-reverse || column || column-reverse; }
弹性包装
如果您检查第一个代码示例,您会发现默认情况下子元素不会在 flex 包装器中堆叠。 这就是flex-wrap
发挥作用的地方:
- nowrap (默认):防止 flex 容器中的项目包装
- wrap:根据需要将项目包装成多行(或列,取决于
flex-direction
) - wrap-reverse:就像
wrap
一样,但行(或列)的数量随着项目的包装而以相反的方向增长
请参阅 DD (@Diegue) 在 CodePen 上的 Pen Flexbox @Toptal - Parent - `flex-wrap` 属性。
.wrapper { flex-wrap: nowrap || wrap || wrap-reverse; }
弹性流
您可以将flex-direction
和flex-wrap
属性组合成一个属性: flex-flow
。
.wrapper { flex-flow: {flex-direction} {flex-wrap}; }
证明内容
该属性用于控制子元素的水平对齐方式:
- flex-start (默认):元素左对齐(类似于带有
text-align: left
内联元素) - flex-end:元素向右对齐(类似于带有
text-align: right
内联元素) - center:元素居中(类似于带有
text-align: center
内联元素) - space-around (魔法开始的地方):每个元素将在每个项目周围使用相同数量的空间进行渲染。 请注意,两个顺序子元素之间的空间将是最外层元素和包装器侧面之间空间的两倍。
- space-between:就像
space-around
一样,除了元素将被相同的距离分开并且包装器的任一边缘附近都没有空间。
注意:记住
flex-direction
,当设置为column
或column-reverse
时,交换轴。 如果设置其中之一,justify-content
将影响垂直对齐,而不是水平对齐。
请参阅 CodePen 上 DD (@Diegue) 的 Pen Flexbox @Toptal - Parent - `justify-content` 属性。
对齐项目
此属性类似于justify-content
,但其效果的上下文是行而不是包装器本身:
- flex-start:元素垂直对齐到包装器的顶部。
- flex-end:元素垂直对齐到包装器的底部。
- center:元素在包装器中垂直居中(最后,实现这一点的安全做法)。
- 拉伸(默认):强制元素占据包装器的全高(应用于行时)和全宽(应用于列时)。
- 基线:将元素垂直对齐到它们的实际基线。
请参阅 CodePen 上 DD (@Diegue) 的 Pen Flexbox @Toptal - Parent - `align-items` 属性。
对齐内容
此属性类似于justify-content
和align-items
但它在垂直轴上工作,并且上下文是整个包装器(而不是像前面的示例那样的行)。 要查看其效果,您需要不止一行:
- flex-start:行与顶部垂直对齐(即从包装器顶部堆叠)。
- flex-end:行与底部垂直对齐(即从包装器底部堆叠)。
- center:行在包装器中垂直居中。
- 拉伸(默认):通常,此属性拉伸元素以利用包装器的整个垂直高度。 但是,如果您设置了元素的某个特定高度,则该高度将被尊重,并且剩余的垂直空间(在该行中,该元素下方)将为空。
- space-around:每一行都将在垂直方向(即,自身下方和上方)周围以相同数量的空间进行渲染。 请注意,两行之间的空间因此将是顶部和底部行与包装边缘之间的空间的两倍。
- space-between :就像
space-around
一样,除了元素将被相同的距离分开,并且包装器的顶部和底部边缘没有空间。
请参阅 CodePen 上 DD (@Diegue) 的 Pen Flexbox @Toptal - Parent - `align-content` 属性。
弹性成长
此属性设置元素应使用的可用空间的相对比例。 该值应该是一个整数,其中 0 是默认值。
假设您在同一个 flex 包装器中有两个不同的元素。 如果两者的flex-grow
值都为 1,它们将平均增长以共享可用空间。 但是,如果一个flex-grow
值为 1,另一个flex-grow
值为 2,如下例所示,则flex-grow
值为 2 的这个值将增长为第一个的两倍。
.wrapper .elements { flex-grow: 1; /* Default 0 */ } .wrapper .elements:first-child { flex-grow: 2; }
请参阅 CodePen 上 DD (@Diegue) 的 Pen Flexbox @Toptal - Children - `flex-grow` 属性。
弹性收缩
与flex-grow
类似,此属性使用整数值设置元素是否“可收缩”。 与flex-grow
类似, flex-shrink
指定弹性项目的收缩系数。

请参阅 CodePen 上 DD (@Diegue) 的 Pen Flexbox @Toptal - Children - `flex-shrink` 属性。
.wrapper .element { flex-shrink: 1; /* Default 0 */ }
弹性基础
此属性用于在分配可用空间并相应调整元素之前定义元素的初始大小。
提示:
flex-basis
不支持calc()
和box-sizing: border-box
在每个浏览器中,所以如果你需要使用其中之一,我建议使用width
(注意你还需要设置flex-basis: auto;
)。
请参阅 DD (@Diegue) 在 CodePen 上的 Pen Flexbox @Toptal - Children - `flex-basis` 属性。
.wrapper .element { flex-basis: size || auto; /* Default auto */ }
柔性
您可以将flex-grow
、 flex-shrink
和flex-basis
属性组合成一个属性: flex
,如下所示:
.wrapper { flex: {flex-grow} {flex-shrink} {flex-basis}; }
提示:如果您打算使用
flex
,请确保定义每个值(即使您想使用默认值),因为某些浏览器可能无法识别它们(常见错误与未定义flex-grow
值有关)。
对齐自我
此属性与align-items
类似,但效果单独应用于每个元素。 可能的值是:
- flex-start:将元素垂直对齐到包装器的顶部。
- flex-end:将元素垂直对齐到包装器的底部。
- center:垂直居中包装内的元素(最后是实现此目的的简单方法!)。
- 拉伸(默认):拉伸元素以占据包装器的整个高度(应用于行时)或包装器的整个宽度(应用于列时)。
- 基线:根据元素的实际基线对齐元素。
请参阅 CodePen 上 DD (@Diegue) 的 Pen Flexbox @Toptal - Children - `align-self` 属性。
命令
Flexbox 中包含的最好的东西之一是能够重新排序元素(使用order
属性),而无需修改 DOM 或使用 JavaScript。 order
属性的工作方式非常简单。 就像z-index
控制项目的渲染顺序一样, order
控制元素在包装器中的定位顺序; 也就是说,具有较低order
值的元素(顺便说一下,它甚至可以是负数)位于具有较高order
值的元素之前。
请参阅 CodePen 上 DD (@Diegue) 的 Pen Flexbox @Toptal - Children - `order` 属性。
.wrapper .elements { order: 1; /* this one will be positioned second */ } .wrapper .elements:last-child { order: -1; /* this one will be positioned first */ }
将它们放在一起:Flexbox 的示例使用
在设计布局时,Flexbox 释放了无限可能。 下面,您可以找到一些 Flexbox 属性的示例用法。
垂直对齐组件
使用 Flexbox,您可以垂直对齐任何东西,包括一次多个元素。 如果没有 Flexbox,您需要使用定位或表格技术,这需要我们创建一个子元素来包含多个元素。 但是使用 Flexbox,您可以抛开这些繁琐而脆弱的技术,只需在包装器中定义一些属性即可,无论容器内的内容更改多少次或更改的类型如何!
.wrapper { display: flex; /* always present for Flexbox practices */ flex-direction: column; /* elements stack */ justify-content: center; /* now that flex-direction is a column, the axis are swapped so this centers the content vertically */ min-height: 100vh /* make sure wrapper is taller enough */ }
请参阅 Pen Flexbox @Toptal - 我们可以提供的实际用途 - CodePen 上的 DD (@Diegue) 垂直对齐。
半/半布局
“半/半”布局是具有两列的全高布局,每列的内容垂直居中。 它通常在“首屏”实现(即,在页面加载后用户向下滚动之前)。
使用更传统的技术,您可以使用浮动元素(每个宽度为 50%)创建此布局,将浮动清除到包装器中(“clearfix” :before
和:after
, overflow: hidden
或带有clear: both;
的古怪<div>
: clear: both;
最后)。 然而,工作量很大,而且结果不如 Flexbox 提供的稳定。
在下面的代码片段中,您将看到设置布局是多么容易,以及孩子如何成为 Flexbox 包装器,因为所有内容也都是垂直对齐的。
外包装:
.wrapper { display: flex; flex-direction: column; /* only for mobile */ }
内包装:
.inner-wrapper { flex-grow: 1; /* Allow the element to grow if there is available space */ flex-shrink: 1; /* Elements shrink at the same rate */ flex-basis: 100%; /* Elements will cover the same amount, if is possible the 100% of the width */ }
请参阅 Pen Flexbox @Toptal - 我们可以提供的实际用途 - CodePen 上 DD (@Diegue) 的 Half-bleed 部分。
全角导航栏按钮
无论元素数量如何,全宽导航栏都会在同一行导航栏项目中平均分配空间。
在下面的示例中,也有一些没有此行为的标志性按钮,表明您可以以任何您想要的方式将两者结合起来。 如果没有 Flexbox,实现这些布局将需要 JavaScript 代码来计算可用空间,然后根据哪些按钮跨越和哪些不跨越以编程方式分配它。
Flexbox 让这变得简单多了。
包装器属性:
.navbar { display: flex; }
跨越子属性:
.navbar-item { flex-grow: 1; /* They will grow */ }
非跨越子属性:
.navbar-other { flex-grow: 0; // They won't grow }
请参阅 Pen Flexbox @Toptal - 我们可以提供的实际用途 - CodePen 上的 DD (@Diegue) 的全出血按钮导航栏。
简介
你有多少次在不同的项目中实现了一组带有图标和文本的信息框?
这种元素的分布在数字营销中最有用,但在软件开发中还有其他用途。 借助 Flexbox 的强大功能,您可以设置一种网格并对齐元素,无论有多少元素。
包装器属性:
.wrapper { display: flex; flex-wrap: wrap; }
子属性:
.blurb { flex-grow: 0; /* elements don't grow */ flex-shrink: 0; /* elements don't shrink in a flexible way */ flex-basis: auto; /* the width of the elements will be set by proportions in `width` due to flex-basis not support workaround */ width: calc(33.33% - 60px); /* calculate proportional width without space taken by padding (workaround for IE 11) */ }
对于平板电脑和移动设备视口,宽度在 50% 和 100% 之间变化。
请参阅 Pen Flexbox @Toptal - 我们可以提供的真实用途 - CodePen 上的 DD (@Diegue) 的 Blurbs。
增强跨浏览器兼容性
Flexbox 的语法在不同的浏览器版本中发生了多次变化。 当使用 Flexbox 实现布局并尝试支持较旧的 Web 浏览器,尤其是较旧版本的 Internet Explorer 时,这可能是一个问题。
幸运的是,Flexbugs 中列出了许多让您的代码在最广泛的 Web 浏览器中运行的技术和变通方法,这是一个很好的资源。 如果您遵循该站点上的信息,您将在不同的 Web 浏览器中获得更好、一致的结果。
前缀任务在这方面特别有用。 要自动为 CSS 规则添加前缀,您可以选择以下工具之一:
红宝石:
- Autoprefixer Rails
- 中间人自动前缀
节点.js:
- PostCSS 自动前缀
- Grunt 自动前缀
- Gulp 自动前缀
开始构建智能布局
Flexbox 是一个很好的工具,可以加快、完善和扩展我们的工作。 限制仅在开发人员的想象中。
如果你需要一些视觉帮助来规划你的下一个布局,你可以试试这个整洁的游乐场:
请参阅 CodePen 上 DD (@Diegue) 的 Pen Flexbox @Toptal - Flexbox 游乐场。
在新窗口中打开它。
随着大多数用户越来越多地采用现代 Web 浏览器,使用 Flexbox 可以让您轻松创建令人惊叹的布局,而无需深入研究凌乱的 JavaScript 代码或制作笨拙的 CSS。