Nested flexbox with same height for nested items - css

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

Related

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?

3 column grid layout spaced out over width with dynamic content

I'm trying to achieve the following layout with dynamic content:
code:
.container {
display: flex;
flex-direction:row;
justify-content:space-between;
}
<div class="container">
<span>Published</span>
<span>Song title</span>
<span>Edit song</span>
</div>
What would be the best way to go about it, taking into account that sometimes the texts in each span don't always appear, I want they layout to be fixed so that even if one of the texts doesn't appear they always remain in the same place. Thanks!
The original code above I tried with display:flex doesn't work because when the text doesn't appear the grid collapses.
add the following css
.container {
display: flex;
flex-direction:row;
justify-content:space-between;
}
https://jsfiddle.net/hxazcg71/

Can I use CSS Flexbox to remove columns?

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

Vertical align using table method?

I'm trying to vertically align using the table/table-cell method.
JSFiddle
<div class="row">
<div class="small-6 columns valign">vertically align me</div>
<div class="small-6 columns"><p>content</p>.....</div>
</div>
.row{
display: table;
}
.valign{
display: table-cell;
vertical-align: middle;
background: grey;
height: 100%;
}
But it's not working, where am I going wrong? I suspect it is something to do with the height of the valign column. How can I get this to stretch to the height of it's parent?
I should also mention in my actual code I have the code nested quite deep in the page, so it's inside article and section tag and another div too.
On some browsers CSS property float does not work with display: table-cell so you should set float: none to table-cell elements in order to make them act like table cells
https://jsfiddle.net/zac926wL/5/

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