Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flex-Basis: 0% causes incorrect overflow in IE11

The problem I have involves flex-basis: 0%; and how IE11 handles it when the user reduces the window's width. Could be related to the bug with box-sizing.

I have a variable number of flex-children, and each child is of unknown width. Each child has arbitrary dynamically-generated content. However, some of this content must have the ability to wrap text.

The flex-container itself must have 100% width and must be able to wrap its children (i.e., flex-wrap: wrap).

Let's assume three flex-children are present, with the last one requiring 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>

The CSS can be defined as follows:

.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;
}

When the window is wide enough, each flex-child should be side-by-side, and the text not collapsed: Correct display - Max-width Window

When the window is shrunken horizontally, the text in the right-most box should begin to break to new lines: Correct Display - Mid-width Window

And when the text can no longer break into more lines, the flex-boxes themselves should begin to break lines: Correct Display - Min-width Window

This works great in most modern browsers but not our friend, IE11. In IE11, when changing the screen size, the text wraps fine, but the flex-children do not wrap at all. Because the flex-children do not wrap, their content overflows into one another: Incorrect IE11 Display - flex-basis: 0%

Changing the flex basis to flex-basis: auto; has the opposite effect: the text will not wrap but the flex-children do, but no content overflows (in this screenshot, the text in the green box should be breaking lines rather than the flex-box breaking into a new line): Incorrect IE11 Display - flex-basis: auto

Most solutions I have seen require having fixed-length flex-children which I cannot afford to have here because they are dynamically generated. I intentionally did not use the flex shortcut property because of some other non-related issues with it. This answer recommends using _:-ms-fullscreen, :root .IE11-only-class { /* IE11 specific properties */ } which might work if I could get around the text-wrapping issue, but I cannot figure that out.

I should also say that I only need this to work on the latest browsers (technically only on certain versions of Chrome and IE11, but having other browsers and versions work as well is a plus).

Here is a code pen showing the problem in full (view in IE11 and Chrome to see the difference).

Does anyone have any ideas as to how to get around this issue?

Remember, the requirements are:

  • unknown number of flex-children of unspecified width
  • certain text must wrap before the flex-boxes wrap
  • flex-children must wrap once the text can no longer wrap more
  • Chrome (I am using 59.0.3071.109) and IE11 (I am using 11.0.9600.18816CO) should behave in the same way.
  • CSS-only solutions are preferred

Thank you.

Update:

A coworker of mine recommended using a separate class for flex-children that do not contain wrappable text. The following HTML and CSS were what he used:

<!--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>

And

/*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;
}

His solution technically fixed the problem as I presented it here, but I forgot to mention another requirement:

  • Within a flex-child, there can be any combination of wrappable text and unwrappable text

His solution does not succeed when changing the third flex-child to:

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

In this case, the text in the second div in the third flex-child flows out of its container, and the text begins wrapping too early.

A codepen showing this almost-working solution can be seen here (note that min-width was removed because it caused further issues on Chrome).

Update 2: I don't think I was clear enough earlier: any, all, or none of the flex-children may have wrappable text. It all depends on the dynamically-generated content. In the example I gave, only the third flex-child has wrappable text, but that might not always be the case.

like image 711
Jonathan Avatar asked Oct 27 '17 16:10

Jonathan


People also ask

What happens when Flex-basis is 0?

Now, when it comes to the property called flex-grow, the default is 0. That means the squares are not allowed to grow to take up the space in the container.

Does Flex work on IE 11?

Note also that Internet Explorer 11 supports the modern display: flex specification however it has a number of bugs in the implementation.

Does Flex not work with IE?

Internet Explorer doesn't fully support Flexbox due to: Partial support is due to large amount of bugs present (see known issues).


2 Answers

Note, this answer were posted prior to the question's 2 updates, which made it partially invalid, though I will leave it for now, someone might need it as is.

After a lot of trial-and-error, I came up with this set up, where I aim to make IE mimic the rest of the browsers behavior as much as possible.

IE need a minimum width on the break-able's parent, so the text won't collapse into 0 width before the element wrap, and as flex-basis needs to be auto in general but 0px on the break-able's parent, the flex-grow's need to be somewhere around 5.

I added the following rules using an IE11 only selector (which I showed in this answer of mine).

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

Updated codepen

Stack snippet

.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>
like image 157
Asons Avatar answered Nov 13 '22 18:11

Asons


This is NOT a preferred solution because it uses Javascript. However, it works.

After creating all flex-children, and whenever the screen size changes, check if the width of each flex-child is less than the width of its content (for this to work, the content must be wrapped with something with display: table-cell). If so, add a minimum width to the flex-child equal to the width of its content. Once a min-width is added, the calculation need not be done again, so no longer check when screen size changes. Only do this on IE11.

I used jquery to implement this solution.

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);
    });
}

The codepen to view this solution can be found here.

Unfortunately, this solution requires additional overhead when managing resources because of the window event.

like image 43
Jonathan Avatar answered Nov 13 '22 19:11

Jonathan