Can I use CSS Flexbox to remove columns? - css

Is there some way CSS flexbox will remove columns (flex items) when the available real estate is small - similar to the functionality provided by FooTable?

The element will tighten up to 0px if needed. Hiding the content can be handled by using overflow: hidden, but beware that this may create problems in other scenarios.
Check the following snippet to see the result:
.container {
display: flex;
}
.child1, .child3 {
flex: 1 0 50%;
}
.child2 {
flex: 1;
overflow: hidden;
}
<div class="container">
<div class="child1">child1</div>
<div class="child2">child2</div>
<div class="child3">child3</div>
</div>
Other suggestions:
Use media queries to hide the content depending on the window size;
Use media queries to apply the overflow property depending on the window size;
If you don't want to hide it, go with flex-wrap to spread your flex items into 2+ rows

Related

How to achieve specific css flexbox layout with multiple columns of different row items [duplicate]

This question already has answers here:
Make a div span two rows in a grid
(2 answers)
Closed 2 years ago.
I'm trying to achieve the flex layout as per the image below. In my code examples, I've not been successful, yet so I can't provide any useful code snippets.
Box 1 would be fixed width and 100% height
Box 2 and 3 would be 50% height and 100% width
Box 4 would be fixed width and 100% height
It would be wrapped in a container DIV (not shown).
Is this correct usage for Flex, or should a grid be used for something like this? I've found an example that manages to get either box 1 or box 4 in position (such as here: Mozilla Flex Example, but not with both.
For layouts with such requirements CSS Grid is a much better choice than Flexbox.
CSS Grid Layout excels at dividing a page into major regions or defining the relationship in terms of size, position, and layer, between parts of a control built from HTML primitives.
Here's a working codepen. You can modify the fixed columns width by changing the grid-template-columns definitions.
Yes, you can do this with flexbox - you will need a container div for box 2 and box 3. You can use something like this:
#layout {
display: flex;
resize: both;
overflow: scroll;
}
#box1, #box4 {
width: 100px;
}
#box2-3 {
flex-grow: 1;
display: flex;
flex-direction: column;
}
#box2, #box3 {
flex-grow: 1;
}
#box1, #box2, #box3, #box4 {
border: 1px solid red;
}
<div id="layout">
<div id="box1">Box 1</div>
<div id="box2-3">
<div id="box2">Box 2</div>
<div id="box3">Box 3</div>
</div>
<div id="box4">Box 4</div>
</div>

Using flex-wrap:wrap but having trouble using pseudo selectors to adjust position of last item

We have an odd number of items inside of a flex: flex-wrap container and at a certain resolution when they wrap the last of the items is over to the left but I want it to (continue to) be to the right.
I googled and found a resource discussing a similar issue at: https://haizdesign.com/css/flexbox-align-last-item-grid-left/
The ::after pseudo-element they applied to achieve this is:
.speakers::after {
content: '';
flex: auto;
}
So I tried to apply this knowledge, but instead use the ::before pseudo-element to try to move my last item over to the right, but I could not get it to work. Below is some HTML and CSS code followed by a link to the CodePen:
#container {
display: flex;
flex-wrap: wrap;
}
.el-width {
min-width: 40%;
}
.last-el::before {
content: '';
flex: auto;
}
<div id="container">
<div class="el-width">Foo</div>
<div class="el-width">Bar</div>
<!-- uncomment to move Baz under Bar
<div class="el-width last-el"> </div>
-->
<div class="el-width last-el">Baz</div>
</div>
https://codepen.io/dexygen/pen/ExaNZYv
As you can see in the HTML if you interpose an actual (empty) div, Baz gets moved under Bar. I've also been able to introduce an actual element in my application and it does likewise. However I'd like to know how or if it can be achieved using ::before
This would be a lot easier with CSS Grid. I leave this here as an alternative answer, in case it helps others.
#container {
display: grid;
grid-template-columns: 40% 40%;
}
.el-width {
border: 1px solid;
}
.last-el {
grid-column-start: 2;
}
<div id="container">
<div class="el-width">Foo</div>
<div class="el-width">Bar</div>
<!-- uncomment to move Baz under Bar
<div class="el-width last-el"> </div>
-->
<div class="el-width last-el">Baz</div>
</div>
Pseudo elements on a flex container are treated as flex items (source).
So the first problem is that the pseudo element in your code is applied to the flex item (.last-el). It needs to be applied to the flex container (#container).
Then, the default order matters. The ::before() pseudo is the first flex item, and an ::after() pseudo would be the last.
So, if you're going to use a pseudo element as a flex item, to bump over an inner item, you need to use the order property to re-arrange the visual order. (Incidentally, this obviates the need to choose between ::before() and ::after().)
#container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.el-width {
flex: 0 0 33.33%;
}
#container::before {
order: 1;
flex: 0 0 33.33%;
content: '';
}
.el-width:nth-child(-n+3) {
order: 0;
}
.el-width:nth-last-child(-n+2) {
order: 2;
}
<div id="container">
<div class="el-width">Item 1</div>
<div class="el-width">Item 2</div>
<div class="el-width">Item 3</div>
<div class="el-width">Item 4</div>
<div class="el-width">Item 5</div>
</div>
The pseudo element method you're describing in your question is explained here:
Properly sizing and aligning the flex item(s) on the last row
A description of the problem, along with potential solutions, can be found here:
Targeting flex items on the last or specific row
And a clean and efficient solution for handling this problem, using CSS Grid, is here:
Equal width flex items even after they wrap
Fixing this is simple and to do it, we use a pseudo element. Going back to our container, (in this case, my container has a class of .speakers)
So they applied the ::after to the container to create a last element, not they apply to the last element last-el. And they did that because they used justify-content: space-between to justify their items leads their last element to unexpected position, which seems to not be of your case. If you want to layout in 2 dimensions, CSS Grid is the best. If you want better browser compatible, then you might already have the answer yourself in the codepen you gave. But I think what you really want might just be the answer that you basically can't solve this by just adding styles to .el-width::before?

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

Nested flexbox with same height for nested items

I am trying to implement a card pattern (similar to material design) making use of flexbox for layout. Each card has a header and a content and uses flexbox to arrange them.
Cards have a fixed width so if a header is long it will wrap, making that header longer. The problem is I want each card in a row to look consistent, so I want each header in a row to have the same height.
The height of the card is already consistent thanks to the outer flexbox. I don't know how to make the headers' height consistent.
the basic layout is:
<div class="flex-container">
<div class="flex-item">
<div class="flex-header">
My header
</div>
<div class="flex-content">
My content
</div>
</div>
<div class="flex-item">
<div class="flex-header">
My header
</div>
<div class="flex-content">
My content
</div>
</div>
</div>
Flexbox css:
.flex-container {
display: flex;
flex-flow: row wrap;
}
.flex-item {
width: 200px;
margin: 10px;
display: flex;
flex-flow: column;
}
.flex-header {
background-color: navy;
font-size: 2em;
}
.flex-content {
}
I also have an example codepen.
The behavior you want is unique found in only one HTML Interface which is the table. In order to avoid all the gripes and lecturing from everyone about using a table for layout, try using the display properties with the values of:
table
table-row
table-cell
For use of these values read this.
CODEPEN
Add min-height in .flex-header
Example:
.flex-header {
background-color: navy;
font-size: 2em;
min-height: 80px;
}
I was looking to make a same layout as you mentioned and after reading the answers here, that it is not possible with just CSS, I tried JS solutions and found this awesome library here.
I've created a codepen example. It might help someone who's looking for the same.
All you need to do is add the library and use the following jQuery code.
$('.item-image').matchHeight({
byRow: true,
property: 'height',
target: null,
remove: false
});
Regards

Fixed width columns with fluid gutters

I know this can be done with columns, but I have to support IE.
I'm trying to get to a layout whose columns are all fixed width, with the gutters being fluid.
I couldn't get this to work with floats, so I settled on using justified inline-block items:
HTML
<div class="wrapper">
<div></div>
<div></div>
<div></div>
<!-- more divs... -->
</div>
CSS
.wrapper {
text-align: justify;
}
.wrapper div {
width: 100px;
display: inline-block;
}
This works wonderfully, but the last row of divs are all aligned to the left: http://jsfiddle.net/EsHh3/
The only solution I found is to add additional unnecessary divs: http://jsfiddle.net/EsHh3/1/
I feel uncomfortable about this, so I'd like to know if there are any other options.
Please don't tell me not to re-invent the wheel. I have not found any fluid grid system that supports fluid gutters.
For what you want to do, I'm afraid a CSS only solution is not available at the moment, much less if you want it to work in IE8.
Since you want to have (a) items that are in the HTML source as a list (b) a variable number of columns depending on available space (c) column spacing depending on width of container I think the solution you'll need would have to employ at least a bit of javascript.
Consider on of the frameworks proposed in the other answers. One I've worked with and could do what you want is Masonry (or the for-pay bigger brother Isotope). (There's also a non-jQuery version of Masonry). You'll have to come up with a function that when the page is resized, recalculates the desired gutter and reconfigures the framework. Something along the lines of calculating x = how many items would fit per line based on the container width and item width and then dividing the remaining space by x-1.
If you want to stick with the idea of adding extra DIV's to the markup, an alternative would be to listen to resize events, and add DIVs as needed based on the width and how many items would fit per line.
ORIGINAL ANSWER, which failed to fit all the criteria.
Since you're relying on text-align: justified the reason the last line doesn't expand to the full width is because there's no line break at the end of it. So to accomplish that we add an extra element with an wrapper:after {} rule, that is also an inline block with a width of 100% so it guaranties a line break.
See fiddle
The CSS ends up something like:
.wrapper {
text-align: justify;
width: 380px;
margin: 0 auto;
}
.wrapper div {
width: 100px;
display: inline-block;
}
.wrapper:after {content: ''; width: 100%; display: inline-block; background: pink; height: 2px; overflow: hidden}
Note that the pink background is there so that you can see where the element is. You might need to play with the border/margin/padding of that extra element or the wrapper so that content that comes after wrapper doesn't gain extra margin. In chrome unfortunately there's a slight missalignment of the last row items, possibly because of the extra space between the last DIV and the fake element.
Hey I don't know why you want a fluid gutter, but I have a simple grid sample which you might want to have a look and if you want to see the css then click the SCSS on the codepen site. Also, if you are learning then this sample is very good start point for how to make your own grid. Also, to avoid yourself reinventing the wheel you might want to try different grid frameworks out there. Just google css grid frameworks.
you can try this:
.wrapper {
text-align: justify;
width: 380px;
margin: 0 auto;
moz-column-count: 3;
-moz-column-gap: 20px;
-webkit-column-count: 3;
-webkit-column-gap: 20px;
column-count: 3;
column-gap: 20px;
}
Updated URL
This is how I would go about it: http://codepen.io/jeremychurch/pen/wmtJz
.container {
display: table;
width: 100%; }
.cell {
display: table-cell; }
.content {
width: 15em;
margin: 0 auto; }
<div class="container">
<div class="cell">
<div class="content">
</div>
</div>
<div class="cell">
<div class="content">
</div>
</div>
<div class="cell">
<div class="content">
</div>
</div>
</div>

Resources