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:
When the window is shrunken horizontally, the text in the right-most box should begin to break to new lines:
And when the text can no longer break into more lines, the flex-boxes themselves should begin to break lines:
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:
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):
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:
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:
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.
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.
Note also that Internet Explorer 11 supports the modern display: flex specification however it has a number of bugs in the implementation.
Internet Explorer doesn't fully support Flexbox due to: Partial support is due to large amount of bugs present (see known issues).
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>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With