Chrome/Safari 未填充 flex 父级的 100% 高度
我想要一个具有特定高度的垂直菜单.
I want to have a vertical menu with a specific height.
每个子元素的高度必须与父元素的高度一致,并且文本居中对齐.
Each child must fill the height of the parent and have middle-aligned text.
孩子的数量是随机的,所以我必须使用动态值.
The number of children is random, so I have to work with dynamic values.
Div .container
包含随机数量的子项 (.item
),它们总是必须填充父项的高度.为了实现这一点,我使用了 flexbox.
Div .container
contains a random number of children (.item
) that always have to fill the height of the parent. To achieve that I used flexbox.
为了使文本与中间对齐,我使用了 display: table-cell
技术.但是使用表格显示需要使用 100% 的高度.
For making links with text aligned to the middle I am using display: table-cell
technique. But using table displays requires using a height 100%.
我的问题是 .item-inner { height: 100% }
在 webkit (Chrome) 中不起作用.
My problem is that .item-inner { height: 100% }
is not working in webkit (Chrome).
- 是否有解决此问题的方法?
- 或者是否有不同的技术让所有
.item
填充父级的高度,文本垂直对齐到中间?
- Is there a fix for this problem?
- Or is there a different technique to make all
.item
fill the height of the parent with text vertical aligned to middle?
这里以jsFiddle为例,应该在Firefox和Chrome中查看
.container {
height: 20em;
display: flex;
flex-direction: column;
border: 5px solid black
}
.item {
flex: 1;
border-bottom: 1px solid white;
}
.item-inner {
height: 100%;
width: 100%;
display: table;
}
a {
background: orange;
display: table-cell;
vertical-align: middle;
}
<div class="container">
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
</div>
推荐答案
解决方案
使用嵌套的弹性容器.
Solution
Use nested flex containers.
摆脱百分比高度.摆脱表属性.摆脱 vertical-align
.避免绝对定位.一直坚持使用 flexbox.
Get rid of percentage heights. Get rid of table properties. Get rid of vertical-align
. Avoid absolute positioning. Just stick with flexbox all the way through.
将 display: flex
应用到弹性项目(.item
),使其成为弹性容器.这会自动设置 align-items:stretch
,它告诉子级 (.item-inner
) 扩展父级的整个高度.
Apply display: flex
to the flex item (.item
), making it a flex container. This automatically sets align-items: stretch
, which tells the child (.item-inner
) to expand the full height of the parent.
重要提示:从 flex 项中删除指定的高度以使此方法起作用. 如果孩子有指定的高度(例如 height: 100%
),那么它将忽略align-items: stretch
来自父级.为了使 stretch
默认工作,孩子的身高必须计算为 auto
(full解释).
Important: Remove specified heights from flex items for this method to work. If a child has a height specified (e.g. height: 100%
), then it will ignore the align-items: stretch
coming from the parent. For the stretch
default to work, the child's height must compute to auto
(full explanation).
试试这个(不更改 HTML):
Try this (no changes to HTML):
.container {
display: flex;
flex-direction: column;
height: 20em;
border: 5px solid black
}
.item {
display: flex; /* new; nested flex container */
flex: 1;
border-bottom: 1px solid white;
}
.item-inner {
display: flex; /* new; nested flex container */
flex: 1; /* new */
/* height: 100%; <-- remove; unnecessary */
/* width: 100%; <-- remove; unnecessary */
/* display: table; <-- remove; unnecessary */
}
a {
display: flex; /* new; nested flex container */
flex: 1; /* new */
align-items: center; /* new; vertically center text */
background: orange;
/* display: table-cell; <-- remove; unnecessary */
/* vertical-align: middle; <-- remove; unnecessary */
}
<div class="container">
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
</div>
jsFiddle 演示
我的问题是 .item-inner { height: 100% }
不起作用webkit (Chrome).
My problem is that
.item-inner { height: 100% }
is not working in webkit (Chrome).
它不起作用,因为您使用百分比高度的方式不符合规范的传统实现.
It's not working because you're using percentage height in a way that doesn't conform with the traditional implementation of the spec.
10.5 内容高度:height
属性
百分比
指定百分比高度.百分比是根据生成框的高度计算的包含块.如果包含块的高度不是明确指定并且此元素不是绝对定位的,该值计算为 auto
.
auto
高度取决于其他属性的值.
auto
The height depends on the values of other properties.
换句话说,要使百分比高度适用于流入子级,父级必须具有设定的高度.
In other words, for percentage height to work on an in-flow child, the parent must have a set height.
在您的代码中,顶级容器具有定义的高度:.container { height: 20em;}
In your code, the top-level container has a defined height: .container { height: 20em; }
三级容器有一个定义的高度:.item-inner { height: 100%;}
The third-level container has a defined height: .item-inner { height: 100%; }
但在它们之间,二级容器–.item
–没有定义的高度.Webkit 认为这是一个缺失的链接.
But between them, the second-level container – .item
– does not have a defined height. Webkit sees that as a missing link.
.item-inner
告诉 Chrome:给我 height: 100%
.Chrome 会查看父级 (.item
) 以供参考并回应:100% 什么?我什么也没看到(忽略那里的 flex: 1
规则).因此,它根据规范应用 height: auto
(内容高度).
.item-inner
is telling Chrome: give me height: 100%
. Chrome looks to the parent (.item
) for reference and responds: 100% of what? I don't see anything (ignoring the flex: 1
rule that is there). As a result, it applies height: auto
(content height), in accordance with the spec.
另一方面,Firefox 现在接受父母的弹性高度作为孩子身高百分比的参考.IE11 和 Edge 也接受弹性高度.
Firefox, on the other hand, now accepts a parent's flex height as a reference for the child's percentage height. IE11 and Edge accept flex heights, as well.
此外,如果与 flex-basis
结合使用,Chrome 将接受 flex-grow
作为适当的父级引用(任何数值都有效)(auto
不会),包括 flex-basis: 0
).然而,在撰写本文时,此解决方案在 Safari 中失败.
Also, Chrome will accept flex-grow
as an adequate parent reference if used in conjunction with flex-basis
(any numerical value works (auto
won't), including flex-basis: 0
). As of this writing, however, this solution fails in Safari.
#outer {
display: flex;
flex-direction: column;
height: 300px;
background-color: white;
border: 1px solid red;
}
#middle {
flex-grow: 1;
flex-basis: 1px;
background-color: yellow;
}
#inner {
height: 100%;
background-color: lightgreen;
}
<div id="outer">
<div id="middle">
<div id="inner">
INNER
</div>
</div>
</div>
1.指定所有父元素的高度
可靠的跨浏览器解决方案是在所有父元素上指定高度.这可以防止丢失链接,基于 Webkit 的浏览器认为这些链接违反了规范.
A reliable cross-browser solution is to specify a height on all parent elements. This prevents missing links, which Webkit-based browsers consider a violation of the spec.
请注意,min-height
和 max-height
是不可接受的.它必须是 height
属性.
Note that min-height
and max-height
are not acceptable. It must be the height
property.
更多详情:使用 CSS height
属性和百分比值
More details here: Working with the CSS height
property and percentage values
2.CSS 相关 &绝对定位
将 position: relative
应用于父级,将 position: absolute
应用于子级.
Apply position: relative
to the parent and position: absolute
to the child.
使用 height: 100%
和 width: 100%
调整子节点的大小,或者使用偏移属性:top: 0
, >右:0
,底部:0
,左:0
.
Size the child with height: 100%
and width: 100%
, or use the offset properties: top: 0
, right: 0
, bottom: 0
, left: 0
.
使用绝对定位,百分比高度可以在没有指定高度的情况下在父级上工作.
With absolute positioning, percentage height works without a specified height on the parent.
3.删除不必要的 HTML 容器(推荐)
button
周围是否需要两个容器?为什么不删除 .item
或 .item-inner
,或两者都删除?虽然 button
元素有时无法作为弹性容器,但它们可以是弹性项目.考虑将 button
设为 .container
或 .item
的子级,并移除无偿标记.
Is there a need for two containers around button
? Why not remove .item
or .item-inner
, or both? Although button
elements sometimes fail as flex containers, they can be flex items. Consider making button
a child of .container
or .item
, and removing gratuitous mark-up.
这是一个例子:
.container {
height: 20em;
display: flex;
flex-direction: column;
border: 5px solid black
}
a {
flex: 1;
background: orange;
border-bottom: 1px solid white;
display: flex; /* nested flex container (for aligning text) */
align-items: center; /* center text vertically */
justify-content: center; /* center text horizontally */
}
<div class="container">
<a>Button</a>
<a>Button</a>
<a>Button</a>
</div>
4.嵌套 Flex 容器(推荐)
摆脱百分比高度.摆脱表属性.摆脱 vertical-align
.避免绝对定位.一直坚持使用 flexbox.
Get rid of percentage heights. Get rid of table properties. Get rid of vertical-align
. Avoid absolute positioning. Just stick with flexbox all the way through.
将 display: flex
应用到弹性项目(.item
),使其成为弹性容器.这会自动设置 align-items:stretch
,它告诉子级 (.item-inner
) 扩展父级的整个高度.
Apply display: flex
to the flex item (.item
), making it a flex container. This automatically sets align-items: stretch
, which tells the child (.item-inner
) to expand the full height of the parent.
重要提示:从 flex 项中删除指定的高度以使此方法起作用. 如果孩子有指定的高度(例如 height: 100%
),那么它将忽略align-items: stretch
来自父级.为了使 stretch
默认工作,孩子的身高必须计算为 auto
(full解释).
Important: Remove specified heights from flex items for this method to work. If a child has a height specified (e.g. height: 100%
), then it will ignore the align-items: stretch
coming from the parent. For the stretch
default to work, the child's height must compute to auto
(full explanation).
试试这个(不更改 HTML):
Try this (no changes to HTML):
.container {
display: flex;
flex-direction: column;
height: 20em;
border: 5px solid black
}
.item {
display: flex; /* new; nested flex container */
flex: 1;
border-bottom: 1px solid white;
}
.item-inner {
display: flex; /* new; nested flex container */
flex: 1; /* new */
/* height: 100%; <-- remove; unnecessary */
/* width: 100%; <-- remove; unnecessary */
/* display: table; <-- remove; unnecessary */
}
a {
display: flex; /* new; nested flex container */
flex: 1; /* new */
align-items: center; /* new; vertically center text */
background: orange;
/* display: table-cell; <-- remove; unnecessary */
/* vertical-align: middle; <-- remove; unnecessary */
}
<div class="container">
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
</div>
相关文章