高度自适应的盒子(或更高)(且不会被压缩)

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您的旅程各个阶段提供云产品。 立即开始使用 价值 200 美元的免费信用额度!

很难在一篇简短的博客文章中概括 Flexbox 的所有优点。 虽然我们 在这里尝试过。 这里,让我们只关注 Flexbox 很好的解决的一个问题:能够让一组任意盒子填充父盒子的所有可用高度。 而且不仅如此,如果需要,还可以扩展超出该高度(不会压缩以适应)。

“盒子”指的是块级元素,例如 div、section、article 等。

默认情况下,这些盒子的高度由它们内部的内容决定。 它们将一个接一个地堆叠起来。 它们的父盒子的高度也可能由它们的组合高度决定,但也可能不同(例如,它被明确设置或它是一个可变值,如浏览器窗口)。 如果父盒子有更大的高度,在下方就会出现空的空间。

我们不能强迫这些盒子均匀地分割那个空间吗? 通过 Flexbox,我们可以做到。

左侧:默认; 右侧:我们想要的效果

假设 HTML 代码如下

<section class="fill-height-or-more">
  <div>
    <!-- stuff -->
  </div>
  <div>
    <!-- stuff -->
  </div>
  <div>
    <!-- stuff -->
  </div>
</section>

然后我们使用父盒子启动 Flexbox

.fill-height-or-more {
  display: flex;
}

并使盒子上下排列(列)而不是默认的左右排列(行)

.fill-height-or-more {
  display: flex;
  flex-direction: column;
}

仅凭这一点,它看起来与我们什么都不做时没有区别。 但是现在我们将 flex 属性应用于子元素,它们将填充空间

.fill-height-or-more > div {
  /* these are the flex items */
  flex: 1;
}

好了 =)。

这里需要详细说明的是,flex: 1; 等同于 flex: 1 1 auto; 它是三个不同属性的简写

flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;

碰巧,让它们能够以相等的方式增长是最常见的需求,因此 flex: 1; 是一个很好的写法。

Flexbox 的优点之一是,它适用于任意数量的盒子。 可以是一个盒子! 可以是 100 个盒子! 无论多少。 如果有额外的空间,空间将被分割和填充。 如果没有,也没关系。

在没有 Flexbox 的时代,我们可能尝试去知道/找出有多少个盒子,然后用百分比设置它们的高度。 这可以填充额外的空间,但是如果盒子过多,就会被压缩。 这是 Flexbox 的另一个优点,它不会压缩这些盒子,以至于它们无法容纳其内容。 所以…

左侧:如果我们使用百分比; 右侧:正常的预期行为

如果我们想更进一步,我们可以使用 Flexbox 将内容也居中到这些盒子中(!) 。 然而,这就是人们对 CSS 感到恼火的地方。 垂直居中很困难。 即使在这里使用 Flexbox,我们也需要将我们拥有的每个 Flex 项目子元素也变成 Flex 容器。 然后使用一个内部包装器,它成为我们居中的 Flex 项目。 所以,仍然需要一个额外的元素。 更新:Tedmotu 做到了,没有额外的元素,非常直接

要居中它,我们再次使方向为上下(列)并使用另一个 Flexbox 属性 justify-content 来居中它。

.fill-height-or-more > div {
  flex: 1;

  display: flex;
  justify-content: center;
  flex-direction: column;
}

这就是 参考指南 派上用场的地方…… 快速找出哪个属性有什么作用。

然后我们得到了这个

查看 CodePen 上 Chris Coyier 的 高度自适应的盒子(或更高) 演示 (@chriscoyier)。

浏览器支持

我只在本文中使用了最新的语法。 Chrome 和 Opera 的最新版本直接支持它。 Firefox 和 Android 的未来版本也将直接支持它。 Safari 和 iOS 支持新的语法,只是使用了 -webkit- 前缀。 Can I Use 提供了完整的故事。

IE 很奇怪。 IE 10 支持 Flexbox 的过渡版本(例如 display: -ms-flexbox;)。 IE 11 支持最新的 Flexbox。 但是,在这个特定的演示中,有些东西坏了。 虽然 .fill-height-or-more 的高度通过使用 min-height 渲染为全高度,但盒子被压缩了。

如果使用 height 而不是 flex 容器,它“可以工作”——但这里的重点是使用 min-height 来避免压缩。 对我来说,这似乎是一个实现错误。

更新: Nirav Zaveri 写信告诉我,在 IE(我测试了 v11)中,flex: 1 不等于 flex: 1 1 auto,即使它应该相等(?)。 如果您设置后者,它可以工作

您可以理解,您可能需要在浏览器支持方面退后一步。 Firefox 27、iOS 6 和 Safari 6 都是非常合法的浏览器支持目标,它们都使用一些变体的老语法,有时带前缀,有时不带前缀。

我们的示例在尽可能完整地支持所有浏览器的情况下看起来像这样

.fill-height-or-more {
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -webkit-flex-direction: column;
  -moz-box-orient: vertical;
  -moz-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
} 

.fill-height-or-more > div {
  -webkit-box-flex: 1;
  -webkit-flex: 1;
  -moz-box-flex: 1;
  -ms-flex: 1;
  flex: 1;
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -moz-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -webkit-flex-direction: column;
  -moz-box-orient: vertical;
  -moz-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
}

天啊。 我的建议? 像我上面那样用现代语法编写,让 Autoprefixer 处理它,它不仅处理前缀,而且还处理老语法。

视频演示

不妨试试? 我 在这里发布了它,我也会嵌入它


另外,为了记录,促使我进行这项工作的真实场景是 这个页面