Chrome/Safari 未填充 100% 的 flex 父级高度 [英] Chrome / Safari not filling 100% height of flex parent

查看:30
本文介绍了Chrome/Safari 未填充 100% 的 flex 父级高度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要一个具有特定高度的垂直菜单.

每个子项必须填充父项的高度并具有居中对齐的文本.

孩子的数量是随机的,所以我必须使用动态值.

Div .container 包含随机数量的子元素 (.item),它们总是必须填充父元素的高度.为了实现这一点,我使用了 flexbox.

为了制作文本与中间对齐的链接,我使用了 display: table-cell 技术.但是使用表格显示需要使用高度 100%.

我的问题是 .item-inner { height: 100% } 在 webkit (Chrome) 中不起作用.

  1. 是否有解决此问题的方法?
  2. 或者是否有不同的技术使所有 .item 填充父级的高度,文本垂直居中对齐?

这里以 jsFiddle 为例,应该在 Firefox 和 Chrome 中查看

.container {高度:20em;显示:弹性;弹性方向:列;边框:5px纯黑色}.物品 {弹性:1;边框底部:1px 纯白色;}.item 内部 {高度:100%;宽度:100%;显示:表;}一种 {背景:橙色;显示:表格单元格;垂直对齐:中间;}

<div class="item"><div class="item-inner"><a>按钮</a>

<div class="item"><div class="item-inner"><a>按钮</a>

<div class="item"><div class="item-inner"><a>按钮</a>

解决方案

解决方案

使用嵌套的弹性容器.

摆脱百分比高度.摆脱表格属性.摆脱vertical-align.避免绝对定位.一直坚持使用 flexbox.

display: flex 应用到弹性项目 (.item),使其成为弹性容器.这会自动设置 align-items:stretch,它告诉子项 (.item-inner) 展开父项的完整高度.

重要:从 flex 项目中删除指定的高度以使此方法起作用. 如果孩子指定了高度(例如 height: 100%),那么它将忽略align-items:stretch 来自父级.要使 stretch 默认工作,孩子的身高必须计算为 auto (完整解释).

试试这个(不改变 HTML):

.container {显示:弹性;弹性方向:列;高度:20em;边框:5px纯黑色}.物品 {显示:弹性;/* 新的;嵌套的弹性容器 */弹性:1;边框底部:1px 纯白色;}.item 内部 {显示:弹性;/* 新的;嵌套的弹性容器 */弹性:1;/* 新的 *//* 高度:100%;<-- 删除;不必要的 *//* 宽度:100%;<-- 删除;不必要的 *//* 显示:表格;<-- 删除;不必要的 */}一种 {显示:弹性;/* 新的;嵌套的弹性容器 */弹性:1;/* 新的 */对齐项目:居中;/* 新的;垂直居中文本 */背景:橙色;/* 显示:表格单元格;<-- 删除;不必要的 *//* 垂直对齐:中间;<-- 删除;不必要的 */}

<div class="item"><div class="item-inner"><a>按钮</a>

<div class="item"><div class="item-inner"><a>按钮</a>

<div class="item"><div class="item-inner"><a>按钮</a>

jsFiddle 演示

<小时>

说明

<块引用>

我的问题是 .item-inner { height: 100% } 不起作用网络套件 (Chrome).

它不起作用,因为您以不符合规范的传统实现的方式使用百分比高度.

<块引用>

10.5 内容高度:height 属性

百分比
指定百分比高度.百分比是相对于生成框的高度计算的包含块.如果包含块的高度不是明确指定并且此元素不是绝对定位的,该值计算为 auto.

auto
高度取决于其他属性的值.

换句话说,要让百分比高度适用于流入的孩子,父母必须有一个设定的高度.

在你的代码中,顶级容器有一个定义的高度: .container { height: 20em;}

三级容器定义了高度:.item-inner { height: 100%;}

但它们之间,是二级容器——.item没有定义的高度.Webkit 将其视为缺失的链接.

.item-inner 告诉 Chrome:给我 height: 100%.Chrome 会查看父级 (.item) 以供参考并做出回应:100% 什么?我什么也没看到(忽略那里的 flex: 1 规则).因此,它根据规范应用 height: auto(内容高度).

另一方面,Firefox 现在接受父级的 flex 高度作为子级百分比高度的参考.IE11 和 Edge 也接受 flex 高度.

此外,Chrome 将接受 flex-grow 作为适当的父引用如果与 flex-basis 结合使用(任何数值都适用(auto 不会),包括 flex-basis: 0).然而,在撰写本文时,此解决方案在 Safari 中失败.

#outer {显示:弹性;弹性方向:列;高度:300px;背景颜色:白色;边框:1px纯红色;}#中间 {弹性增长:1;弹性基础:1px;背景颜色:黄色;}#内{高度:100%;背景颜色:浅绿色;}

<div id="中间"><div id="内部">内

<小时>

四种解决方案

1.指定所有父元素的高度

可靠的跨浏览器解决方案是在所有父元素上指定高度.这可以防止丢失链接,而基于 Webkit 的浏览器会将其视为违反规范.

注意min-heightmax-height 是不可接受的.它必须是 height 属性.

此处有更多详细信息:使用 CSS height 属性和百分比值

2.CSS 相对 &绝对定位

position:relative 应用于父级,将 position: absolute 应用于子级.

使用 height: 100%width: 100% 来调整子元素的大小,或者使用偏移属性:top: 0, 右:0下:0左:0.

使用绝对定位,百分比高度在父级上没有指定高度的情况下工作.

3.删除不必要的 HTML 容器(推荐)

button 周围是否需要两个容器?为什么不删除 .item.item-inner 或两者?尽管 button 元素有时无法作为弹性容器,但它们可以是弹性项目.考虑使 button 成为 .container.item 的子项,并删除无偿标记.

这是一个例子:

.container {高度:20em;显示:弹性;弹性方向:列;边框:5px纯黑色}一种 {弹性:1;背景:橙色;边框底部:1px 纯白色;显示:弹性;/* 嵌套的 flex 容器(用于对齐文本)*/对齐项目:居中;/* 垂直居中文本 */对齐内容:居中;/* 水平居中文本 */}

<a>按钮</a><a>按钮</a><a>按钮</a>

4.嵌套 Flex 容器(推荐)

摆脱百分比高度.摆脱表格属性.摆脱vertical-align.避免绝对定位.一直坚持使用 flexbox.

display: flex 应用到弹性项目 (.item),使其成为弹性容器.这会自动设置 align-items:stretch,它告诉子项 (.item-inner) 展开父项的完整高度.

重要:从 flex 项目中删除指定的高度以使此方法起作用. 如果孩子指定了高度(例如 height: 100%),那么它将忽略align-items:stretch 来自父级.要使 stretch 默认工作,孩子的身高必须计算为 auto (完整解释).

试试这个(不改变 HTML):

.container {显示:弹性;弹性方向:列;高度:20em;边框:5px纯黑色}.物品 {显示:弹性;/* 新的;嵌套的弹性容器 */弹性:1;边框底部:1px 纯白色;}.item 内部 {显示:弹性;/* 新的;嵌套的弹性容器 */弹性:1;/* 新的 *//* 高度:100%;<-- 删除;不必要的 *//* 宽度:100%;<-- 删除;不必要的 *//* 显示:表格;<-- 删除;不必要的 */}一种 {显示:弹性;/* 新的;嵌套的弹性容器 */弹性:1;/* 新的 */对齐项目:居中;/* 新的;垂直居中文本 */背景:橙色;/* 显示:表格单元格;<-- 删除;不必要的 *//* 垂直对齐:中间;<-- 删除;不必要的 */}

<div class="item"><div class="item-inner"><a>按钮</a>

<div class="item"><div class="item-inner"><a>按钮</a>

<div class="item"><div class="item-inner"><a>按钮</a>

jsFiddle

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 contains a random number of children (.item) that always have to fill the height of the parent. To achieve that I used flexbox.

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%.

My problem is that .item-inner { height: 100% } is not working in webkit (Chrome).

  1. Is there a fix for this problem?
  2. Or is there a different technique to make all .item fill the height of the parent with text vertical aligned to middle?

Example here jsFiddle, should be viewed in Firefox and 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.

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.

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.

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).

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 demo


Explanation

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 Content height: the height property

percentage
Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly and this element is not absolutely positioned, the value computes to 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.

In your code, the top-level container has a defined height: .container { height: 20em; }

The third-level container has a defined height: .item-inner { height: 100%; }

But between them, the second-level container – .itemdoes not have a defined height. Webkit sees that as a missing link.

.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, 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.

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>


Four Solutions

1. Specify a height on all parent elements

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.

Note that min-height and max-height are not acceptable. It must be the height property.

More details here: Working with the CSS height property and percentage values

2. CSS Relative & Absolute Positioning

Apply position: relative to the parent and position: absolute to the child.

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. Remove unnecessary HTML containers (recommended)

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.

Here's an example:

.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. Nested Flex Containers (recommended)

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.

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.

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).

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

这篇关于Chrome/Safari 未填充 100% 的 flex 父级高度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆