使弹性项目伸展全高并垂直居中其内容

Make flex items stretch full height and vertically center their content

我有一个带有一些项目的水平弹性框(即 flex-direction: row,即并排)。每个项目可以是单行文本,也可以有多行。我想垂直对齐每个弹性项目的内容。

如果每个项目都有透明背景,我可以轻松使用 align-items: center。但是,我希望每个项目都垂直拉伸,因为我想将背景(或者可能是边框,或者可能是可点击区域)设置为整个可用高度。

到目前为止,我知道:

可在 http://codepen.io/denilsonsa/pen/bVBQNa

获得演示

ul {
  display: flex;
  flex-direction: row;
}
ul.first {
  align-items: stretch;
}
ul.second {
  align-items: center;
}
ul > li {
  flex-grow: 1;
  flex-shrink: 0;
  flex-basis: 5em;
  text-align: center;
}
ul > li:nth-child(2) {
  background: #CFC;
}

/* Visual styles, just ignore. */
html, body { font-family: sans-serif; font-size: 25px; }
ul, li { list-style: none; margin: 0; padding: 0; }
ul { background: #CCF; width: 25em; }
<ul class="first">
  <li>Sample</li>
  <li><span>span</span></li>
  <li><span>multiple</span> <span>span</span></li>
  <li>text <span>span</span></li>
  <li>multi<br>line</li>
</ul>
<hr>
<ul class="second">
  <li>Sample</li>
  <li><span>span</span></li>
  <li><span>multiple</span> <span>span</span></li>
  <li>text <span>span</span></li>
  <li>multi<br>line</li>
</ul>


类似问题:

使用 flex-direction:column 创建 li 弹性容器。我想这就是你所追求的。

html,
body {
  font-family: sans-serif;
  font-size: 25px;
}
ul,
li {
  list-style: none;
  margin: 0;
  padding: 0;
}
ul {
  background: #CCF;
  width: 25em;
  display: flex;
  flex-direction: row;
}
ul.first {
  align-items: stretch;
}
ul > li {
  flex-grow: 1;
  flex-shrink: 0;
  flex-basis: 5em;
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  /*outline: 1px dotted #444;*/
}
ul > li:nth-child(2) {
  background: #CFC;
}
<ul class="first">
  <li>Sample</li>
  <li><span>span</span>
  </li>
  <li><span>multiple</span>  <span>span</span>
  </li>
  <li>text <span>span</span>
  </li>
  <li>multi
    <br>line</li>
</ul>

I want each item to be stretched vertically, because I want to set a background (or maybe borders, or maybe it is a clickable region) to the entire available height.

您可以在不更改 HTML 结构的情况下实现此布局。不需要额外的容器。

您已经有了一个主伸缩容器和一组伸缩项目。只需将这些 flex 项目放入嵌套的 flex 容器中。这将使您能够将内容与 flex 属性对齐。

(因为您提到您可能需要可点击区域,所以我从 li 切换到 a 元素。)

nav {
  display: flex;
  background: #CCF;
  width: 25em;
}

nav > a {
  flex: auto;  /* flex-grow: 1, flex-shrink: 1, flex-basis: auto */
  text-align: center;
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: center;
}
nav > a:nth-child(2) {
  background: #CFC;
}

html, body {
  font-family: sans-serif;
  font-size: 25px;
}
<nav>
  <a href="">Sample</a>
  <a href=""><span>span</span></a>
  <a href=""><span>multiple</span> <span>span</span></a>
  <a href="">text <span>span</span></a>
  <a href="">multi<br>line</a>
</nav>

revised codepen

请注意,直接放在 flex 容器中的内容被包裹在 匿名 flex 项目:

来自规范:

4. Flex Items

Each in-flow child of a flex container becomes a flex item, and each contiguous run of text that is directly contained inside a flex container is wrapped in an anonymous flex item.

因此,由于文本自动包裹在 flex 项目中,您可以保持每个项目的完整高度(align-items: stretch 从主容器)并将内容垂直居中(align-items: center 从嵌套容器)。

弹性子项也可以是弹性父项。

*,
*:before,
*:after {
  box-sizing: inherit;
}
html {
  box-sizing: border-box;
  font-family: sans-serif;
  font-size: 25px;
}
body {
  display: flex;
  flex-flow: column nowrap;
  background-color: #333;
  overflow: hidden;
}
html,
body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}

.List {
  padding: 0;
  margin: 0;
  background: #CCF;
  width: 25em;
  list-style: none;
  display: flex;
  flex-flow: row nowrap;
  justify-content: center;
}

.ListItem {
  flex-basis: 5em;
  display: flex;
  flex-flow: row wrap;
  text-align: center;
  align-items: center;
}

.ListItem:nth-child(2) {
  background: #CFC;
}

.ListItem__content {
  width: 100%;
}
<ul class="List">
  <li class="ListItem">
    <span class="ListItem__content">Sample</span>
  </li>
  <li class="ListItem">
    <span class="ListItem__content">span</span>
  </li>
  <li class="ListItem">
    <span class="ListItem__content">multiple <br> span</span>
  </li>
  <li class="ListItem">
    <span class="ListItem__content">span</span>
  </li>
  <li class="ListItem">
    <span class="ListItem__content">multi<br>line</span></li>
</ul>

不幸的是,使用问题中发布的确切标记无法达到预期效果。

解决方案涉及:

  • <li> 上设置 display: flex;
  • 正在将 <li> 内容包装到另一个元素中。
    • 这是必需的,因为 <li> 现在是一个弹性容器,所以我们需要另一个元素来防止实际内容变成弹性项目。
    • 在这个解决方案中,我引入了一个 <div> 元素,但它可能是其他元素。
  • 现在 <li> 是一个 flex 容器,它只包含一个 child,我们可以使用 align-items and/or justify-content 来对齐这个新的并且只有 child.

DOM 树看起来像这样:

<ul> flex-parent, direction=row
 ├ <li> flex-item && flex-parent && background && JavaScript clickable area
 │  └ <div> flex-item as a single transparent element
 │     ├ Actual contents
 │     └ Actual contents
 ├ …

注意:这个答案中的解决方案使用了 2 个嵌套的弹性框。 使用 3 个嵌套的 flex 框,因为它具有扩展 <a> 元素以填充整个 <li> 的额外挑战。哪一个是首选取决于每个案例。如果可以,我会接受这两个答案。

/* New code: this is the solution. */
ul > li {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

/* Old code below. */
ul {
  display: flex;
  flex-direction: row;
  align-items: stretch;
}
ul > li {
  flex-grow: 1;
  flex-shrink: 0;
  flex-basis: 5em;
  text-align: center;
}
ul > li:nth-child(2) {
  background: #CFC;
}

/* Visual styles, just ignore. */
html, body { font-family: sans-serif; font-size: 25px; }
ul, li { list-style: none; margin: 0; padding: 0; }
ul { background: #CCF; width: 25em; }

button:focus + ul {
    font-size: 14px;
    width: auto;
}
<button>Click here to set <code>width: auto</code> and reduce the font size.</button>

<!-- New code: there is a single <div> between each <li> and their contents. -->
<ul>
  <li><div>Sample</div></li>
  <li><div><span>span</span></div></li>
  <li><div><span>multiple</span> <span>span</span></div></li>
  <li><div>text <span>span</span></div></li>
  <li><div>multi<br>line</div></li>
</ul>