I have the following arrangement via flexbox with flex-wrap and elements able to stretch using flex-grow:
Each item has a margin on all sides. This is to separate the items from each other, but the side effect is the whole block has margins which I'd like to collapse. It could be done with rules like nth-child(-n+3) { margin-top: 0; } but because the container size could vary, there could be any number of items per row and any number of rows. So I'm wondering if flex-box has any way to collapse the outer margins in a setup like this, while retaining the margins between items.
JSBin
The HTML is simply 6 items inside a container.
The CSS (Sass) is as follows:
.container
display: flex
flex-wrap: wrap
background: #eef
align-items: stretch
.item
flex-grow: 1
margin: 1em
border: 1px solid black
padding: 1em
min-width: 6em
It's a bit of a hack, but you can add a negative margin on the flex container to cancel out the items' margins along the edges, and then move its "background" styling to a parent wrapper-element.
Updated JSBin
Updated CSS (SASS):
.wrapper
background: #eef
border: 1px solid darkgray
.container
display: flex
flex-wrap: wrap
margin: -1em
.item
flex-grow: 1
margin: 1em
border: 1px solid black
padding: 1em
min-width: 6em
Another hack is to split the margin responsibilities between container and item, each caring about half (say $margin is 1em):
• container cares about its bottom margin and half left + half-right of items:
.container {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap; // Go to next line if not enough space
padding-top: 0; // Let items handle top
padding-left: $margin/2; // Handle half of left
padding-bottom: $margin; // Handle bottom
padding-right: $margin/2; // Handle half of right
}
• items care about top and half left + half right:
.item {
flex-grow: 1; // Use available space
margin-left: $margin/2; // Handle other half of left
margin-right: $margin/2; // Handle other half of right
margin-top: $margin; // Handle top
}
Regarding items size, you can set a width if you want items to look the same.
.item.fixed {
width: 15em;
}
See a demo here.
Related
How can I get all elements to fit in a container element that is fixed to the size of the window?
I have a container element that is fixed position and flexbox, it does not stay within window. The menu is 50px and I want the main element to fill the remainder of the window height.
I have a container my-app and inside it, 2 vertically stacked elements (flex-direction = column). It works as expected in Chrome but not Edge or Firefox.
my-app {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
app-menu {
border-bottom: 2px solid black;
width: 100%;
height: 50px;
background: lightcoral;
box-sizing: border-box;
}
app-my-view {
display: flex;
flex: 1;
width: 100%;
background: lightgreen;
}
https://stackblitz.com/edit/2-column-scroll-v2
I've got it working by using a fixed position menu sticking to the top and using padding to offset menu height in the main content area. However I thought it would be better to use approach with 2 stacked elements without using fixed menu .
See here: https://stackblitz.com/edit/2-column-scroll-v1
I am adding 3 columns that are 400px wide max and adding space between them using space-between.
.wrap {
display: flex;
flex-wrap: wrap;
align-content: stretch;
justify-content: space-between;
}
.item {
width: 100%;
max-width: 400px;
}
When I make the screen size smaller, the items are not responsive. They just collapse below each other. If I remove flex-wrap I start getting more than 3 columns per row and they are below 400px.
How can I get 3 responsive columns with space between in flex?
Percent for the width can't be used because the space between items has to look the same at any screen size.
You should drop width: 100% if you do not want them to occupy the whole width of the parent. And since you are using flex on the parent, you might as well use flex properties on the children and have these:
.item {
flex-basis: 33%; /* <-- Added in lieu of the width */
max-width: 400px;
margin: 0px 5px; /* <-- Added to give left/right margins */
}
If you only have those 3 children in the parent, then you could also do this:
.item {
flex-grow: 1; /* <-- Lets them grow equally */
flex-shrink: 1; /* <-- Lets them shrink equally. OPTIONAL as 1 is the default */
max-width: 400px;
margin: 0px 5px; /* <-- Added to give left/right margins */
}
The shorthand for the last one is this:
.item {
flex: 1; /* <-- Lets them grow/shrink equally */
max-width: 400px;
margin: 0px 5px; /* <-- Added to give left/right margins */
}
Also, if you only have those 3 children in the parent, you may want to remove flex-wrap: wrap; from .wrapper if you do not want the children elements to wrap. It will not happen in this case, since the children have percentage widths which add up to 100%. But it could be confusing and it contradicts with your intent.
If you want three columns, change the width property to 33% in your .item declaration instead of 100%.
JSFiddle example
Currently, all your "columns" are fighting to be 100% of the parent node. Here's a great explanation of using css flex from css-tricks.com.
I love flexbox and I love bootstrap also. But looks like flexbox features is kind of useless with bootstrap flex for some frequent cases and a lot of custom tweaking is required
For example I use .col-**-* to make grid and add child classes for custom styles, like background
My common problem with nested child is that child doesn't behave as flex child and do not fill the container.
I have to add .child block do .col-**-* to make background and tweak margin/paddings, which is not very handy. Are there any better ways to do so?
http://codepen.io/dpmango/pen/VPKKMw
body
.row
.col-sm-6
.child.child--red
p This block is bigger than sibling! This block is bigger than sibling! This block is bigger than sibling! This block is bigger than sibling! This block is bigger than sibling!
.col-sm-6
.child.child--blue
p I want to grow :-
CSS
// demo
.col-sm-6
padding-top: 20px
padding-bottom: 20px
background: black
border: 1px solid red
// OK - it's same height and stretched
.child
color: white
padding: 30px
&--red
background: tomato
&--blue
background: blue
//this one is not same height
By using display: flex and flex: 1 / flex-basis: 100% it grows
.col-sm-6
padding-top: 20px
padding-bottom: 20px
background: black
border: 1px solid red
display: flex
.child
flex: 1 /* fill remaining height */
flex-basis: 100% /* set full width */
Updated codepen
Or like this, using flex-direction: column and flex: 1
.col-sm-6
padding-top: 20px
padding-bottom: 20px
background: black
border: 1px solid red
display: flex
flex-direction: column /* full width by default */
.child
flex: 1 /* fill remaining height */
Updated codepen 2
I'm trying to make a chat layout. So i have 3 divs, activeUSer - top, messages middle (has to fill the space between 1 and 3), actions - bottom
Now, I've put flex-direction row. and it works fine. I needed the bottom div to grow if the input grows (if you have 2 or more lines of writing)
It worked ok untill I added display:flex to the Actions div (bottom). I needed another flex layout for input and buttons. Now it does not care for the padding i've set on the last div
Here is my codepen https://codepen.io/capraruioan/pen/XKWxrV
#content {
height: 300px;
display: flex;
flex-direction: column;
}
.activeUser {
height: 66px;
background-color: yellow;
}
.Messages {
flex: 1 1 100%;
}
.Actions {
flex-grow: 1;
display: flex;
padding-top: 2px;
padding-bottom: 20px;
}
.aa { //the inputbox
border: 1px solid black;
min-height: 10px
}
fixed it by letting display default on the 3rd div and placing a div with display flex inside
Because examples rule: http://jsfiddle.net/rudiedirkx/wgue7/
How do I get the bars to the bottom instead of the top? Now they're sticking to the top of the container (#bars) but I want them sticking to the bottom.
As you can see, I don't know the height of the highest bar, so I don't know the height of the container.
These q+a don't help: Vertically align floating divs, Vertically align floating DIVs
Should be simple, right? If it helps: it only has to work in decent browsers.
PS. Number of bars is variable (not in the example) and their heights are. Only their widths are static. Positioning absolute won't help, because the container div doesn't have measurements.
This will do the trick:
#bars {
display: table-cell;
border: solid 1px black;
}
#bars > div {
display: inline-block;
vertical-align: bottom;
width: 5px;
background-color: #999;
margin-left: 2px;
}
#bars > div:first-child {
margin-left: 0;
}
It uses display: table-cell; on the parent div, which by default has vertical-align: baseline; applied. This changes the need for float: left; on the child divs and allows us to use display: inline-block;. This also removes the need for your CSS clear fix.
EDIT - Per #thirtydot's comments, adding vertical-align: bottom; to the child divs removes the gap at the bottom.
Therefore, I changed CSS above and jsFiddle. I kept the display: table-cell; so that the parent div wraps the child divs with 0 padding and looks nice and snazzy!
FLEXBOX! Flexbox is the most bestest.
Example: http://jsfiddle.net/rudiedirkx/7FGKN/
Flexbox makes this ridiculously simple (and not to forget correct):
#container {
display: flex; /* or inline-flex */
flex-flow: row nowrap; /* is default: columns along the main-axis (row) and no wrapping to next lines */
align-items: flex-end; /* bottom */
}
#container > div {
/* margin etc here, but nothing layoutish */
}
That's it Two lines of CSS: display: flex and align-items: flex-end.