使弹性项目伸展全高,并垂直居中其内容 [英] Make flex items stretch full height and vertically center their content
问题描述
我有一个水平的弹性框(即 flex-direction:row
,即并排)和几个项目。每个项目可以是一行文本,也可以有多行。我想垂直对齐每个Flex项目的内容。
如果每个项目都有一个透明的背景,我可以很容易地使用 align-items:中心
。然而,我希望每个项目都垂直拉伸,因为我想设置一个背景(或者可能是边框,或者可能是一个可点击的区域)到整个可用的高度。
<到目前为止,我知道:
- 拉伸:
align-items:stretch
- 对齐:
align-items:center
- 拉伸和对齐: / li>
演示可在和和问题23442692 和问题27729619 和问题25311541 问本质上相同的东西,但是他们要么有一个单一的元素,弹性项目。只要我们有混合的内容,可能与多个元素,这些解决方案不起作用。
不幸的是,在使用问题中发布的确切标记时,不可能达到预期效果。 解决方案包括:
- 在
< li>上设置
display:flex;
。 - 将
< li>
内容包装到另一个元素中。
- 因为
< li>
现在是flex容器,所以我们需要另一个元素以防止实际内容变成弹性项目。
- 在此解决方案中,我引入了
< div>
元素,但它可以
- 因为
- 现在
< li> 是一个flex容器,它只包含一个孩子,我们可以使用 align-items
和/或justify-content
来对齐这个
DOM树看起来像这样:
< ul> flex-parent,direction = row
├< li> flex-item&& flex-parent&&背景&& JavaScript可点击区域
│└< div> flex-item作为一个透明元素
│├实际内容
│└实际内容
├...
注意:此答案中的解决方案使用2个嵌套的弹性框。 Michael_B的解决方案使用3个嵌套柔性盒,因为它具有扩展< a>
元素来填充整个< li>
。哪一个是首选取决于每种情况。如果可以的话,我会接受这两个答案。
/ *新代码:这是解决方案。 * / ul> li {display:flex; flex-direction:column; justify-content:center; align-items:center;} / *下面的旧代码。 * / 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;} / *视觉样式,忽略。 * / html,body {font-family:sans-serif; font-size:25px; } ul,li {list-style:none;保证金:0;填充:0; } ul {background:#CCF;宽度:25em; } button:focus + ul {font-size:14px; width:auto;}
< button>点击这里设置< code> width:auto< / code>并减少字体大小。< / button><! - 新代码:有一个< div>在每个< li>和他们的内容。 - >< UL> <李>< DIV>样品< / DIV>< /锂> <李>< DIV><跨度>跨度< /跨度>< / DIV>< /锂> <李>< DIV><跨度>多< /跨度> <跨度>跨度< /跨度>< / DIV>< /锂> < li>< div>文字< span> span< / span>< / div>< / li> <李>< DIV>多<峰; br>线474; / DIV>< /立GT;< / UL>
I have a horizontal flex box (i.e. flex-direction: row
, i.e. side-by-side) with a few items. Each item can be a single line of text, or can have multiple lines. I want to vertically-align the contents of each flex item.
If each item had a transparent background, I could easily use align-items: center
. However, 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.
So far, I know:
- Stretching:
align-items: stretch
- Aligning:
align-items: center
- Stretching and aligning: ???
Demo available at 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>
Similar questions:
- Question 14012030 and question 23442692 and question 27729619 and question 25311541 ask essentially the same thing, but they either have a single element or plain text as child of each flex item. As soon as we have mixed content, possibly with multiple elements, those solutions do not work.
- Question 19026884 is unrelated, the issue there was the wrong markup.
Unfortunately, it is impossible to achieve the desired effect while using the exact markup posted in the question.
The solution involves:
- Setting
display: flex;
on<li>
. - Wrapping the
<li>
contents into another element.- This is required because
<li>
is now a flex container, so we need another element to prevent the actual contents from becoming flex items. - In this solution, I introduced a
<div>
element, but it could have been other element.
- This is required because
- Now that
<li>
is a flex container and it contains only a single child, we can usealign-items
and/orjustify-content
to align this new and only child.
The DOM tree looks like this:
<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
├ …
Note: The solution in this answer uses 2 nested flex boxes. The solution by Michael_B uses 3 nested flex boxes, because it has the added challenge of expanding the <a>
element to fill the entire <li>
. Which one is preferred depends on each case. If I could, I would accept both answers.
/* 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>
这篇关于使弹性项目伸展全高,并垂直居中其内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!