当您将 CSS 属性应用于元素时,幕后会发生很多事情。 例如,假设我们有一些像这样的 HTML 代码
<div class="parent">
<div class="child">Child</div>
<div class="child">Child</div>
<div class="child">Child</div>
</div>
然后我们编写一些 CSS 代码...
.parent {
display: flex;
}
从技术上讲,这并非我们上面编写的那一行 CSS 代码应用的唯一样式。 事实上,这里将对 .child
元素应用一大堆属性,就好像我们自己编写了这些样式一样
.child {
flex: 0 1 auto; /* Default flex value */
}
这很奇怪!为什么这些元素即使我们没有编写该代码也会应用这些额外的样式? 嗯,这是因为一些属性具有默认值,然后我们打算覆盖这些默认值。 而且,如果我们在编写 CSS 时不知道正在应用这些样式,那么我们的布局就会变得非常混乱且难以管理。
上面的 flex
属性被称为 CSS 简写属性。 实际上,这个属性是在同时设置三个独立的 CSS 属性。 所以,我们上面编写的代码与编写以下代码相同
.child {
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
}
所以,简写属性将一堆不同的 CSS 属性捆绑在一起,以方便一次编写多个属性,就像 background
属性一样,我们可以编写这样的代码
body {
background: url(sweettexture.jpg) top center no-repeat fixed padding-box content-box red;
}
我尽量避免使用简写属性,因为它们可能会非常混乱,而且我经常倾向于编写长格式版本,因为我的大脑无法解析长长的属性值行。 但对于 flexbox 而言,建议使用简写,这很奇怪……也就是说,直到您了解到 flex
属性正在进行大量工作,并且它的每个子属性都与其他属性相互作用。
此外,默认样式是一件好事,因为我们大多数情况下不需要知道这些 flexbox 属性的作用。 例如,当我使用 flexbox 时,我倾向于编写类似这样的代码
.parent {
display: flex;
justify-content: space-between;
}
我甚至不需要关心子元素或对它们应用了哪些样式,这很棒! 在这种情况下,我们将子项并排对齐,然后在它们之间均匀地间距。 两行 CSS 代码就能为您提供强大的功能,这是 flexbox 和这些继承样式最棒的地方——如果您只是想始终做同样的事情,您不必了解所有底层的复杂性。 它非常聪明,因为所有这些复杂性都隐藏在视线之外。
但是,如果我们想了解 flexbox(包括 flex-grow
、flex-shrink
和 flex-basis
属性)是如何工作的? 我们用它们可以做哪些很酷的事情?
直接访问 CSS-Tricks 年鉴 就可以了!
开个玩笑。 让我们从一个简化的快速概述开始,然后回到应用于子元素的默认 flex
属性
.child {
flex: 0 1 auto;
}
这些默认样式告诉子元素如何拉伸和扩展。 但是,每当我看到它被使用或被覆盖时,我发现将这些简写属性这样理解很有帮助
/* This is just how I think about the rule above in my head */
.child {
flex: [flex-grow] [flex-shrink] [flex-basis];
}
/* or... */
.child {
flex: [max] [min] [ideal size];
}
第一个值是 flex-grow
,它被设置为 0
,因为默认情况下,我们不希望元素扩展(大多数情况下)。 相反,我们希望每个元素都取决于它内部内容的大小。 以下是一个示例
.parent {
display: flex;
}
我在上面的每个 .child
元素中都添加了 contenteditable
属性,这样您就可以单击它并输入更多内容。 看一下它是如何响应的? 这是 flexbox 项目的默认行为:flex-grow
设置为 0
,因为我们希望元素根据它内部的内容进行增长。
但是! 如果我们要将 flex-grow
属性的默认值从 0
更改为 1
,像这样...
.child {
flex: 1 1 auto;
}
然后所有元素将占据 .parent
元素的相等部分,但只有当它们的内容长度相同时。
这与编写以下代码完全相同...
.child {
flex-grow: 1;
}
…并忽略其他值,因为这些值已经默认设置好了。 我认为,在我开始使用灵活布局时,这让我困惑了很长时间。 我会看到添加了 flex-grow
的代码,并想知道其他样式来自哪里。 这就像一个让我抓狂的谋杀悬案,我无法弄清楚。
现在,如果我们想让其中一个元素比其他元素增长更多,我们只需要执行以下操作
.child-three {
flex: 3 1 auto;
}
/* or we could just write... */
.child-three {
flex-grow: 3;
}
即使 flexbox 已经进入了浏览器十年,这段代码看起来也很奇怪吗? 对于我来说确实如此。 在阅读简写代码时,我需要额外的脑力来思考“最大值、最小值、理想尺寸”,但这随着时间的推移会变得更容易。 无论如何,在上面的示例中,前两个子元素将占用比例相同的空间,但第三个元素将尝试增长到其他元素的三倍空间。
现在,这里事情变得奇怪了,因为这一切都取决于子元素的内容。 即使我们将 flex-grow
设置为 3
,就像我们在上面的示例中所做的那样,然后添加更多内容,布局也会做一些奇怪的事情,比如这样
第二列现在占据了太多空间! 我们稍后会回到这里,但现在,记住 flex 项的内容会影响 flex-grow
、flex-shrink
和 flex-basis
的协同工作方式非常重要。
好了,现在是 flex-shrink
。 请记住,这是简写中的第二个值
.child {
flex: 0 1 auto; /* flex-shrink = 1 */
}
flex-shrink
告诉浏览器元素的最小尺寸应该是多少。 默认值为 1
,这意味着“始终占用相同数量的空间”。 但是! 如果我们将该值设置为 0
,像这样
.child {
flex: 0 0 auto;
}
…那么我们现在告诉这个元素根本不要缩小。 保持相同的大小,你这个该死的元素! 基本上这就是 CSS 代码要表达的意思,它也会完全按照指示去做。 我们稍后会回到这个属性,等我们看一下简写中的最后一个值。
flex-basis
是默认情况下添加到 flex
简写中的最后一个值,它是我们告诉元素保持理想尺寸的方式。 默认情况下,它被设置为 auto
,这意味着“使用我的高度或宽度”。 所以,当我们将父元素设置为 display: flex
时...
.parent {
display: flex;
}
.child {
flex: 0 1 auto;
}
在浏览器中,我们会默认获得以下结果
请注意,默认情况下,所有元素的宽度都是它们内容的宽度? 这是因为 auto
表示元素的理想大小由其内容定义。 为了让所有元素占据父元素的整个空间,我们可以将子元素设置为 width: 100%
,或者我们可以将 flex-basis
设置为 100%
,或者我们可以将 flex-grow
设置为 1
。
这些都有道理吗? 这很奇怪,对吧! 仔细想想就会明白。 这些简写值中的每一个都会影响其他的值,这就是为什么建议首先编写这个简写,而不是彼此独立地设置这些值。
好的,继续。 当我们编写类似这样的代码时...
.child-three {
flex: 0 1 1000px;
}
我们在这里告诉浏览器将 flex-basis
设置为 1000px
,或者说“请、请、请尽可能占据 1000px
的空间”。 如果不可能,那么元素将根据其他元素的比例占据那么多的空间。
您可能会注意到,在较小的屏幕上,第三个元素实际上并没有达到 1000px
! 这是因为它只是一个建议。 我们仍然应用了 flex-shrink
,它告诉元素缩小到与其他元素相同的大小。
此外,向其他子元素添加更多内容也会在这里产生影响
现在,如果我们想阻止这个元素完全缩小,我们可以编写类似这样的代码
.child-three {
flex: 0 0 1000px;
}
请记住,flex-shrink
这里面的第二个值,通过将其设置为 0,我们实际上是在说“永远不要缩小,你这个混蛋”。 这样它就不会缩小了。 这个元素甚至会超出父元素,因为它永远不会比 1000px
宽更小
现在,如果我们将 flex-wrap
设置为父元素,所有这些都会发生变化
.parent {
display: flex;
flex-wrap: wrap;
}
.child-three {
flex: 0 0 1000px;
}
我们会看到以下结果
这是因为,默认情况下,flex 项将尝试适应一行,但 flex-wrap: wrap
会完全忽略这一点。 现在,如果这些 flex 项无法适应相同的空间,它们会换行。
无论如何,这只是 flex
属性相互碰撞的一些方式,以及为什么了解这些属性在底层的运作方式如此重要。 这些属性中的每一个都可能影响其他属性,如果您不了解一个属性是如何工作的,那么您基本上就不了解任何一个属性是如何工作的——这确实让我在开始深入研究之前感到困惑!
但总而言之
- 尝试使用
flex
简写 - 这样做时,请记住最大值、最小值和理想尺寸
- 请记住,元素的内容也会影响这些值之间的协同工作方式。
很棒的文章!
很棒的文章! 我仍然难以理解 flex-box 及其神奇的行为,但是您将它看成“最大值、最小值、理想尺寸”的方式确实让记忆和理解变得更容易。 谢谢!
很棒的文章,谢谢,我想我可能可以用 flexbox,而无需每次都参考指南!
非常好的文章! 这篇文章帮助我更多地了解了 flexbox。
我通常不会在第三方表格上评论,但这次我觉得有必要评论!
我想说,除了事实——这些事实非常准确——你的写作方式非常棒!你一直保持着我的注意力,太棒了!另外,我对你的内容的易读性表示赞赏,初学者可以理解所有内容,而更有经验的用户可以滚动(或阅读)内容以找到他们要查找的部分。
继续努力!我认为你将是一位出色的文案撰稿人/博主。
不错的教程,帮助我很多,请继续发布文章。
它们将占用 .parent 元素的相等部分, *只有当它们的内容长度相同时* 。
没错。这个细节非常重要。希望这篇文章能得到修正,这样初学者在使用 flexbox 时就不会遇到问题。收到错误的信息比完全不知道更糟糕。
您好,我在使用 flexbox 和截断文本时遇到了问题。
我想裁剪掉多余的文本,但当我在 flexbox 中使用它时,它不起作用。但是如果我使用浮动,它又可以工作了。你能帮我吗?
我参考了 这篇文章,但它仍然帮不了我。也许我没有理解 flexbox 的工作原理。
例如: https://jsfiddle.net/95mgc083/
在
.detail
中添加overflow: hidden
,并将a
元素的所有样式转移到.name
要在
flex-item
中截断文本,需要在父元素(flex-item
)中添加overflow: hidden
我发现 这个 CodePen 有点帮助。
谢谢,伙计!这篇帖子让我能够第一次(自我在前端工作以来)理解“flex-grow/shrink/basis”问题。<3 因为我大多数时间都在使用默认值,并没有覆盖它们,现在我迫不及待地想要迎接需要这些知识的挑战。(
使用 Dave Geddes 的 Flexbox Zombies 游戏来更好地理解它。
感谢这个教程,我一直没有理解 flex-grow/shrink/basis 的工作原理。
不错,这帮助我理解了很多。谢谢。
很棒的帖子!每天都会回来看它,以便将其牢记心中。
只想重申一下,“flex” 属性被父元素的所有子元素继承,因此,如果您显式更改父元素的 flex 简写属性,这些更改将被子元素继承。出于某种原因,我感到困惑,以为需要单独定位子元素的 flex 属性。我想,实际上你在哪里设置 flex 属性并不重要。你可以在父元素上设置它,也可以在子元素上设置它。无论如何,再次感谢!
很棒的帖子。当我把它记住为 [max] [min] 和 [ideal] 时,现在对我来说完全有意义了。谢谢!
谢谢,
[max] [min] 和 [ideal]
这件事太棒了。你会说最好不要将高度/宽度与 flex 结合使用(如果可以避免的话)?只是好奇你对这个问题有什么看法。我认为我对 flexbox 的很多困惑都源于你在文章中描述的东西以及人们经常使用高度/宽度。最小和最大被错误地使用了,因为实际上 flex-grow 显示的是尺寸的潜在增加(即 flex-basis),而 flex-shrink 显示的是原始尺寸(即特定元素的 flex-basis)的潜在减少(损失)。你可以把它更好地理解为初始资本的盈亏。它本身并不是最小或最大资本。不幸的是,作者误解了主题,在著名的 CSS 门户网站上发布它,让事情变得更糟。
如何使用 flexbox 创建一个水平滚动图片库,其中图片大小在一定范围内可响应?
我已经做到了这一点
每个图片下面的文本区域的高度不是问题,我认为我已经很好地解决了这个问题。
理想情况下,图片在最大和最小尺寸之间可响应,图片数量不确定,具体取决于使用情况。最初显示的图片数量应由包含 div 的宽度决定。我不想使用媒体查询。
我真的很感谢任何帮助:)
flex-shrink
是元素最小尺寸的解释是错误的。Flex shrink 实际上表示(就像 flex grow 一样,但方向相反)可用空间将如何重新分配。
缩小情况下的“可用”空间当然就是负的。
因此,从所有需要的空间(想想包裹容器外部的溢出空间)中,这些空间是元素在被 flex shrink 压缩后完全适合该包装器所必需的,每个元素都必须放弃一部分,根据每个元素的 flex shrink 系数。
这并不意味着它们是最终尺寸,而是每个元素将放弃多少个负空间的份额。
将它与金融界中的股权稀释进行比较,当一家公司引入投资者时,投资者注入流动性并获得股份,从而将所有创始人的股权份额推向更小的范围。
稍后我将发布一篇更详细的文章,其中包含有关空元素或有或没有强制边距或填充的元素的示例,以便我们的开发人员同行能够更好地理解如何在该领域编写高质量的代码。
不幸的是,Chris 没有接受我在一些有用领域做出贡献的一些评论,因为我在这里写我的意见,所以我不知道我的帖子是否会被看到。
我倡导尽可能使用最简单和最强大的代码,因此,如果评论符合博主的好意,我也很欣赏它的效率。如果不是,为了用户更大的利益,也许这些评论将有助于其他人的页面。我认为好的观点应该被听到,而不是被挡在门外。
谢谢!
太棒了,谢谢。
这太棒了,我一开始也很困惑,我还搜索了很多,但现在我明白了整个想法。
感谢你!我认为我现在明白了这个概念……我认为!:D
这表示 0 和 1 意味着相同的东西,这显然是不正确的。
0 表示根本不缩小。1 表示按比例缩小 1 倍,具体取决于所有可缩小的同级需要缩小多少。2 表示按比例缩小 2 倍。
假设你有三个 flex 同级需要总共缩小 100px,第一个子元素的
flex-shrink: 2
,而其他两个子元素的flex-shrink: 1
。第一个子元素将缩小 50px,而另外两个将缩小 25px。我以为
flex-grow: 3
表示flex: 3 1 0
,而不是flex: 3 1 auto
。我是否误解了什么?你的问题让我也有同样的疑问。我相信 flex-grow 不会影响 flex-shrink 和 flex-basis 的默认值,它们分别是 1 和 auto。但是,flex: 1 将 flex-shrink 设置为 1,并将 flex-basis 设置为 0。
简而言之,
flex-grow: 1; = flex: 1 1 auto;
flex: 1; = flex: 1 1 0;
解释得很好。
非常接地气的解释!非常有价值。
有史以来最好的解释,谢谢。
对于 CSS 初学者来说,这是一个非常好的解释,谢谢!
谢谢!你真是个了不起的人
这个页面太棒了。写作风格很容易理解。它完全符合我的思维过程,使这些概念更容易理解。像 Mozilla 开发者网络上的信息那样的其他资源缺乏正常的写作,只包含定义属性的最低限度信息,但对于初学者来说,这可能是一个真正的挑战。这种风格很容易变得难以理解的专业术语。我无法足够强调这个资源的有效性。