Flex-Basis: 0% 在 IE11 中导致不正确的溢出

Flex-Basis: 0% causes incorrect overflow in IE11

我遇到的问题涉及 flex-basis: 0%; 以及当用户减小 window 的宽度时 IE11 如何处理它。可能与 box-sizing.

的错误有关

我有可变数量的 flex-children,每个 child 的宽度未知。每个 child 都有任意 dynamically-generated 内容。但是,其中一些内容必须能够换行。

flex-container 本身必须有 100% 宽度并且必须能够包裹它的 children(即 flex-wrap: wrap)。

假设存在三个 flex-children,最后一个需要 text-wrapping:

<div class="flex-container">
  <div class="flex-child">
    <div>This text should not overlay other flex-children.</div>
  </div>
  <div class="flex-child">
    <div>This text should not overlay other flex-children.</div>
  </div>
  <div class="flex-child">
    <div class="text-break">This text should break on new lines when the container shrinks down</div>
  </div>
</div>

CSS可以定义如下:

.flex-container {
  display: flex;
  flex-wrap: wrap;
  width: 100%;
}

.flex-child {
  flex-grow: 1;
  flex-shrink: 0;
  flex-basis: 0%;
  white-space: nowrap;
  padding: 5px;
}

.text-break {
  white-space: pre-wrap;
}

当 window 足够宽时,每个 flex-child 应该是 side-by-side,并且文本不会折叠:

当 window 水平收缩时,right-most 框中的文本应开始换行:

并且当文本不能再分行时,flex-boxes 本身应该开始分行:

这适用于大多数现代浏览器,但不适用于我们的朋友 IE11。在 IE11 中,当更改屏幕大小时,文本很好地换行,但 flex-children 根本不换行。因为 flex-children 不换行,它们的内容会相互溢出:

将 flex basis 更改为 flex-basis: auto; 会产生相反的效果:文本不会换行但 flex-children 会换行,但内容不会溢出(在此屏幕截图中,绿色框中的文本应该换行而不是 flex-box 换行):

我见过的大多数解决方案都需要 fixed-length flex-children,但我在这里负担不起,因为它们是动态生成的。我故意没有使用 flex 快捷方式 属性 因为它有一些其他的 non-related 问题。 建议使用 _:-ms-fullscreen, :root .IE11-only-class { /* IE11 specific properties */ } 如果我可以解决 text-wrapping 问题,这可能会起作用,但我无法弄清楚。

我还应该说我只需要它在最新的浏览器上工作(技术上只在某些版本的 Chrome 和 IE11 上工作,但其他浏览器和版本也能工作是一个加号)。

这里 code pen 显示了完整的问题(在 IE11 和 Chrome 中查看区别)。

有没有人知道如何解决这个问题?

记住,要求是:

谢谢。

更新:

我的一位同事建议为 flex-children 使用单独的 class,不包含可换行的文本。下面的HTML和CSS是他用的:

<!--HTML-->
<div class="flex-container">
  <div class="flex-child child-1">
    <div>This text should not overlay other flex-children.</div>
  </div>
  <div class="flex-child flex-child-without-textwrap child-2">
    <div>This text should not overlay other flex-children.</div>
  </div>
  <div class="flex-child flex-child-with-textwrap child-3">
    <div class="text-break">This text should break on new lines when the container shrinks down</div>
  </div>
</div>

/*CSS*/
.flex-container {
  display: flex;
  flex-wrap: wrap;
}

.flex-child {
  flex-grow: 1;
  flex-shrink: 1;
  padding: 5px;
  white-space: nowrap;
}

.flex-child-without-textwrap {
  flex-basis: auto;
}

.flex-child-with-textwrap {
  min-width: 200px;
  flex-basis: 0%;
}

.text-break {
  white-space: pre-wrap;
}

他的解决方案在技术上解决了我在此处提出的问题,但我忘了提及另一个要求:

将第三个flex-child改为:

时,他的解决方案没有成功
<div class="flex-child flex-child-with-textwrap child-3">
  <div class="text-break">This text should break on new lines when the container shrinks down</div>
  <div>This text should not break on new lines</div>
</div>

在这种情况下,第二个 div 中的文本在第三个 flex-child 中流出其容器,并且文本过早开始换行。

可以看到显示此 almost-working 解决方案的代码笔 here(请注意,min-width 已被删除,因为它在 Chrome 上引起了进一步的问题)。

更新二: 我认为我之前说得不够清楚:flex-children 的任何、全部或 none 可能有可换行的文本。这完全取决于 dynamically-generated 内容。在我给出的示例中,只有第三个 flex-child 具有可换行的文本,但情况可能并非总是如此。

注意,这个答案是在问题的 2 次更新之前发布的,这使得它部分无效,但我暂时保留它,有人可能需要它。

经过反复试验,我想出了这个设置,我的目标是让 IE 尽可能模仿其他浏览器的行为。

IE 需要 break-able 的父元素的最小宽度,因此文本在元素换行前不会折叠为 0 宽度,并且 flex-basis 通常需要 autobreak-able 的父 0px flex-grow 需要在 5.

左右

我使用仅 IE11 选择器(我在 中展示)添加了以下规则。

_:-ms-fullscreen, :root .flex-child {
  flex-basis: auto;
}
_:-ms-fullscreen, :root .child-3 {
  flex: 5 0 0px;
  min-width: 80px;
}

Updated codepen

堆栈片段

.wrapper {
  width: 80%;
}

.flex-container {
  display: flex;
  flex-wrap: wrap;
  width: 100%;
}

.flex-child {
  flex: 1 0 0%;
  white-space: nowrap;
  padding: 5px;
}

_:-ms-fullscreen, :root .flex-child {
  flex-basis: auto;
}
_:-ms-fullscreen, :root .child-3 {
  flex: 5 0 0px;
  min-width: 80px;
}

.text-break {
  white-space: pre-wrap;
}

/*Add backgrounds for display*/
.child-1 {
  background-color: pink;
}
.child-2 {
  background-color: lightblue;
}
.child-3 {
  background-color: lightgreen;
}
<div class="wrapper">
  <div class="flex-container">
    <div class="flex-child child-1">
      <div>This text should not overlay other flex-children.</div>
    </div>
    <div class="flex-child child-2">
      <div>This text should not overlay other flex-children.</div>
    </div>
    <div class="flex-child child-3">
      <div class="text-break">This text should break on new lines when the container shrinks down</div>
    </div>
  </div>
</div>

不是首选解决方案,因为它使用Javascript。但是,它有效。

在创建所有 flex-children 之后,每当屏幕尺寸发生变化时,检查每个 flex-child 的宽度是否小于其内容的宽度(为此,内容必须用带有display: table-cell)。如果是这样,将最小宽度添加到 flex-child 等于其内容的宽度。一旦加上了min-width,就不用再计算了,所以屏幕尺寸变化时不再检测。仅在 IE11 上执行此操作。

我使用 jquery 来实现这个解决方案。

HTML:

<div class="flex-container">
    <div id="1" class="flex-child child-1">
        <div class="content-container">This text should not overlay other flex-children.</div>
    </div>
    <div id="2" class="flex-child child-2">
        <div class="content-container">This text should not overlay other flex-children.</div>
    </div>
    <div id="3" class="flex-child child-3">
        <div class="content-container">
            <div class="text-break">This text should break on new lines when the container shrinks down</div>
            <div>This text should not break on new lines</div>
        </div>
    </div>
</div>

CSS:

.flex-container {
    display: flex;
    flex-wrap: wrap;
    width: 100%;
}

.flex-child {
    flex-grow: 1;
    flex-shrink: 0;
    flex-basis: 0%;
    white-space: nowrap;
    padding: 5px;
}

.text-break {
    white-space: pre-wrap;
}

.content-container {
    display: table-cell;
}

Jquery:

if (!!window.MSInputMethodContext && !!document.documentMode) {//if IE11
    $(".flex-child").each(function (i, elem) {
        var $flex_child = $(elem);
        var child_id = $flex_child.attr("id");

        //add resize event to window
        $(window).on("resize." + child_id, function () {
            var width_of_flex_child = $flex_child.outerWidth();
            var content_width = $flex_child.children(".content-container").outerWidth();

            if (width_of_flex_child < content_width) {
                $flex_child.css("min-width", content_width + "px");

                //remove event
                $(window).off("resize." + child_id);
            }
        }).trigger("resize." + child_id);
    });
}

可以找到查看此解决方案的codepen here

不幸的是,由于 window 事件,此解决方案在管理资源时需要额外的开销。