Izak Filmalter 写信给我
在我正在开发的网站上,有一个导航栏包含几个元素:一个搜索输入框、用户的全名和一些图标。 图标的宽度是固定的,用户名是可变的,而搜索栏应该占据可用空间的剩余部分。
无论我尝试什么,当用户名长度动态变化时,我都无法让搜索栏使用所有可用空间且不多不少。
我已经回复了 Izak,但我也将在此处分享该解决方案。 **Flexbox!** 我相信,Flexbox 是一款出色的布局工具,这一点并不奇怪。 我 有一篇关于 Flexbox 的指南,可以作为很好的参考。
好消息是,使用 Flexbox 布局可以轻松实现这一点。 我们将详细说明,但以下几行代码基本上就可以完成任务。
.bar {
display: flex;
}
.search {
flex: 1;
}
分步指南
让我们假设使用以下标记。 这里没有什么意外。 我只是将搜索输入框包裹在一个 <div>
中,主要是因为我不习惯将输入框作为 Flex 项目,但您可能无论如何都需要一个包装元素(如 <form>
),因为您可能会有一个 <label>
等等。
<div class="bar">
<div class="icon icon-1"></div>
<div class="icon icon-2"></div>
<div class="icon icon-3"></div>
<div class="username">
Emily Blunt
</div>
<div class="search">
<input type="search" placeholder="search..." />
</div>
</div>

使它们水平对齐并居中
.bar {
display: flex;
align-items: center;
}

让我们确保该栏与浏览器窗口一样宽。 我们可以轻松地设置 100% 的宽度。 但每当我这样做时,就会提醒我应该 使用 box-sizing: border-box; ——否则,该容器上的任何填充或边框都会使其宽度超过 100%,这是最糟糕的情况。
*, *:before, *:after {
box-sizing: inherit;
}
html {
box-sizing: border-box;
}
.bar {
display: flex;
align-items: center;
width: 100%;
background: #eee;
padding: 20px;
}

对于最终技巧
.search {
/* take up the rest of the remaining space */
flex: 1;
}
.search input {
width: 100%;
}

它将按以下方式工作

现在我们进入了 Flexbox 世界,我们可以随意更改事物的顺序并获得相同的良好间距效果。 order 属性默认为 0,因此任何正值都会将该 Flex 项目置于末尾,负值则置于开头。 然后按顺序排列,就像 z-index
一样。
.bar-2 .username {
order: 2;
}
.bar-2 .icon-3 {
order: 3;
}
.bar-3 .search {
order: -1;
}
.bar-3 .username {
order: 1;
}

响应式设计 (RWD) 奖励!
Flexbox 对响应式设计非常友好,因为我们可以非常轻松地交换顺序和大小,甚至可以换行。 让我们使我们的演示换行,并使搜索和用户名宽度充满整个容器。
@media (max-width: 650px) {
.bar {
flex-wrap: wrap;
}
.icon {
order: 0 !important;
}
.username {
order: 1 !important;
width: 100%;
margin: 15px;
}
.search {
order: 2 !important;
width: 100%;
}
}

演示
开始吧
查看 CodePen 上 Chris Coyier (@chriscoyier) 编写的笔 Flexbox 重新排序。
浏览器支持
如今,提到 Flexbox 就不得不提浏览器支持问题。 与往常一样,您可以查阅 Can I Use。 IE 9 是剩下的最大限制因素。 如果您需要支持它,则必须找到其他方法。 否则,在 旧/新/过渡 语法之间,您 会没事的。 我们在这里没有使用任何奇怪的东西。
诀窍只是 使用 Autoprefixer,它可以很好地处理 Flexbox。 使用它时,此演示中的 Flexbox 属性/值变为
.bar {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
}
.search {
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
}
.bar-2 .username {
-webkit-order: 2;
-ms-flex-order: 2;
order: 2;
}
但我需要更好的回退方案!
一种可能性是使用 Modernizr 检测 Flexbox 支持。 它将在 html 元素上放置一个类名,例如
<html class="no-flexbox">
您可以使用它来使用不同的布局技术。
.no-flexbox .bar {
display: table;
border-spacing: 15px;
padding: 0;
}
.no-flexbox .bar > * {
display: table-cell;
vertical-align: middle;
white-space: nowrap;
}
.no-flexbox .username {
width: 1px;
}
效果很好。

这不是唯一可能的方法。 您可以使用内联块或浮动以及使用 JavaScript 测量内容。 或者您可以使用一个真正的表格。 网页,兄弟,总有办法。
我看到了一个 JavaScript 插件的想法! Flexbox 语法,但如果它检测到您使用的是旧版浏览器,它会自动将 Flexbox 转换为表格布局。
James,你看起来像马克·扎克伯格。
*给 Flexbox 一个大大的拥抱,因为它太棒了!*
所以,我的问题是:99% 的时间您都会保留元素的顺序……那么,如果您可以使用表格单元格(具有更广泛的浏览器支持)实现相同的效果,为什么还要使用支持有限的 Flexbox 呢?
这似乎是一个非常合理的问题。 我也在等待对此进行更多解释。
我认为这篇文章的意义不是强迫人们使用 Flexbox。 而是为他们提供比表格单元格“hacky 方法”更现代的解决方案。 就我个人而言,我将实现 Flexbox 并学习它。 并通过 Modernizr 提供回退方案。
我同意您可以从中学习,我从未说过您不能。 但我不同意将表格单元格显示称为“hacky”的说法,事实上,它是一种完全可行且非 hacky 的方法……
是的,你说得对,它不是 hacky,用词不当 :) 就说它是一种鲜为人知/默默无闻的布局方式吧。(顺便说一句,我一直在使用它)
以下是一些我想说的事情
您好,Chris,我同意您的观点 #1,尽管这样做很常见。 在您的观点 #2 中,这是正确的,尽管正如我提到的,我的问题是在大多数情况下您不需要所有这些灵活性。 关于您的观点 #3,我不会将 IE 6/7 纳入表格,但 Flexbox 不受 IE 9 支持,而 IE 9 与您提到的浏览器相比仍然有很多用户。
我认为,任何以非预期方式使用的东西本质上都是一种 hacky 的用法。 display: table-cell 仅适用于表格单元格;它之所以 hacky,仅仅是因为工具栏不是表格。 我甚至会说,将浮动用于布局是一种 hack,尽管它已经成为多年的事实标准——它只是并非其预期用途,这就是它工作起来如此不直观的原因。 很长一段时间内,根本没有非 hacky 的方法来做到这一点。
这并不是说 hacky 总是不好的。 有时候,即使有“正确”的方法来做事情,hack 也更实用。 但它们仍然是 hack,您应该始终意识到它们可能会在难以发现的场景中表现出不可预测的行为。
您好,Javier,关于灵活性的一点,我认为您可能不太确定是否需要它,因为情况会随着时间而改变。 因此,我认为最好有一个使用纯 CSS 排序事物的选项。
我知道与旧版浏览器的兼容性问题,但您过去也可能对我们今天广泛使用的“box-sizing: border-box;”模型说过同样的话。
我以为是施密特。约翰·雅各布·金格海默·施密特。
是的……是施密特。但我现在只是暴露了我的年龄。但是,嘿,施密特就是这样,对吧?
我转向 Flexbox 而不是 display:table 的主要原因是后者不允许使用任何定位。
例如,最近我需要一个搜索栏(与这里给出的示例非常相似),带下拉/弹出菜单……使用 display:table 做起来非常非常棘手。使用 Flexbox,则轻而易举。
运行完美:http://davidwalsh.name/table-cell-position-absolute
我不认为这完美无缺。为了在 FF 中使其正常工作,必须在父元素上指定高度 100%,这将导致各种问题。
我爱上了 Flex <3
Flexbox 在 IE9+ 或 IE10+ 中有效吗?
有人为 Flexbox 制作了回退方案使其在旧版浏览器中有效吗?我认为没有解决方案 =(
好吧,这是一个棘手的问题。我认为最好的方法是结合使用 Modernizr 和 table-cell 而不是 Flexbox。
为什么这里使用
!important
?因为特异性。我不建议 Chris 在使用
!important
时这样做,但我理解他为什么这样做。如果您查看前面的代码块,您会看到像“.bar-3 .username”这样的后代选择器……为了覆盖这些选择器,他选择使用“.username”在 MQ 样式中保持简单。但这不会覆盖前面的选择器。所以他使用
!important
来使其覆盖。再说一遍,我不建议这样做,因为您可以重复选择器,一切都会好起来……但是如果您独自工作并且理解自己在做什么,那么我想这是一种方法。我只是不明白添加
!important
与重复选择器有什么区别。主要是因为这样它会命中所有三个栏。只是不写三个选择器到一个复合选择器中来覆盖它们的一种廉价方法。
在大型生产应用程序中肯定不推荐这样做。但我更喜欢它,而不是人为地提高特异性。至少使用
!important
,您知道这是一个需要修复的问题。不错的文章……易于理解
不错的帖子,谢谢 Chris,Flex 万岁 :)
非常棒,Chris。
一如既往的完美时机。
在 7 年后开始重新编写网站,天啊,它看起来太老旧了。
我目前假设再过 7 年我才会再次这样做。
这篇文章让我信服了。
纯粹的 HTML 5,使用 Flexbox 替换浮动 div,这就是我将要采用的方式。
谢谢老兄。