Flexbox expands outside container instead of wrapping - html

I have 3 flexboxes each inside the other. The outermost flexbox(.flex-1) holds the title and the next flexbox(.flex-2), which holds the button and the innermost flexbox(.flex-3), which holds a few .items. Ideally, the items will flow down and then when there is no space left (based on the size of the outermost box) should wrap to the right. This works if a height is explicitly set on .flex-3, but I am not able to do that because the title varies in height.
Instead, it overflows and items are shown below the border of .flex-1, as well as flex-2 expanding to fit them and overflowing.
.title{width: 100%}
.flex-1{ /* Title and flex-2 */
display: flex;
flex-direction: column;
width: 700px;
height: 700px;
border: 4px black solid;
}
.flex-2{ /* flex-3 and button */
display: flex;
flex-direction: row;
border: 3px #333 solid;
align-items: flex-start;
}
.flex-3{ /* contains items */
display: flex;
flex-direction: column;
flex-wrap: wrap;
border: 2px #888 solid;
flex-grow: 1;
}
.item{
display: block;
width: 200px;
height: 150px;
border:1px #DDD solid;
}
<div class='flex-1'>
<h3 class='title'>THIS IS A TITLE</h3>
<div class='flex-2'>
<div class='flex-3'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
<button>BTN</button>
</div>
</div>

The problem seems to be caused by the CSS property align-items on .flex-2.
Try removing this.

Related

How can I distance these 2 divs in a flex column? [duplicate]

To set the minimal distance between flexbox items I'm using margin: 0 5px on .item and margin: 0 -5px on container. For me it seems like a hack, but I can't find any better way to do this.
#box {
display: flex;
width: 100px;
margin: 0 -5px;
}
.item {
background: gray;
width: 50px;
height: 50px;
margin: 0 5px;
}
<div id='box'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
CSS gap property:
There is a new gap CSS property for multi-column, flexbox, and grid layouts that works in newer browsers now! (See Can I use link 1; link 2). It is shorthand for row-gap and column-gap.
#box {
display: flex;
gap: 10px;
}
CSS row-gap property:
The row-gap CSS property for both flexbox and grid layouts allows you to create a gap between rows.
#box {
display: flex;
row-gap: 10px;
}
CSS column-gap property:
The column-gap CSS property for multi-column, flexbox and grid layouts allows you to create a gap between columns.
#box {
display: flex;
column-gap: 10px;
}
Example:
#box {
display: flex;
flex-wrap: wrap;
width: 200px;
background-color: red;
gap: 10px;
}
.item {
background: gray;
width: 50px;
height: 50px;
border: 1px black solid;
}
<div id='box'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
Flexbox doesn't have collapsing margins.
Flexbox doesn't have anything akin to border-spacing for tables (edit: CSS property gap fulfills this role in newer browsers, Can I use)
Therefore achieving what you are asking for is a bit more difficult.
In my experience, the "cleanest" way that doesn't use :first-child/:last-child and works without any modification on flex-wrap:wrap is to set padding:5px on the container and margin:5px on the children. That will produce a 10px gap between each child and between each child and their parent.
Demo
.upper {
margin: 30px;
display: flex;
flex-direction: row;
width: 300px;
height: 80px;
border: 1px red solid;
padding: 5px; /* this */
}
.upper > div {
flex: 1 1 auto;
border: 1px red solid;
text-align: center;
margin: 5px; /* and that, will result in a 10px gap */
}
.upper.mc /* multicol test */ {
flex-direction: column;
flex-wrap: wrap;
width: 200px;
height: 200px;
}
<div class="upper">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>
<div class="upper mc">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>
This is not a hack.
The same technique is also used by bootstrap and its grid, though, instead of margin, bootstrap uses padding for its cols.
.row {
margin:0 -15px;
}
.col-xx-xx {
padding:0 15px;
}
Flexbox and css calc with multiple rows support
Hello, below is my working solution for all browsers supporting flexbox. No negative margins.
Fiddle Demo
.flexbox {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.flexbox > div {
/*
1/3 - 3 columns per row
10px - spacing between columns
*/
box-sizing: border-box;
margin: 10px 10px 0 0;
outline: 1px dotted red;
width: calc(1/3*100% - (1 - 1/3)*10px);
}
/*
align last row columns to the left
3n - 3 columns per row
*/
.flexbox > div:nth-child(3n) {
margin-right: 0;
}
.flexbox::after {
content: '';
flex: auto;
}
/*
remove top margin from first row
-n+3 - 3 columns per row
*/
.flexbox > div:nth-child(-n+3) {
margin-top: 0;
}
<div class="flexbox">
<div>col</div>
<div>col</div>
<div>col</div>
<div>col</div>
<div>col</div>
</div>
Take a note this code can be shorter using SASS
Update 2020.II.11
Aligned columns on the last row to the left
Update 2020.II.14
Removed margin-bottom in the last row
You can use & > * + * as a selector to emulate a flex-gap (for a single line):
#box { display: flex; width: 230px; outline: 1px solid blue; }
.item { background: gray; width: 50px; height: 100px; }
/* ----- Flexbox gap: ----- */
#box > * + * {
margin-left: 10px;
}
<div id='box'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
If you need to support flex wrapping, you can use a wrapper element:
.flex { display: flex; flex-wrap: wrap; }
.box { background: gray; height: 100px; min-width: 100px; flex: auto; }
.flex-wrapper {outline: 1px solid red; }
/* ----- Flex gap 10px: ----- */
.flex > * {
margin: 5px;
}
.flex {
margin: -5px;
}
.flex-wrapper {
width: 400px; /* optional */
overflow: hidden; /* optional */
}
<div class='flex-wrapper'>
<div class='flex'>
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>
</div>
</div>
You can use transparent borders.
I have contemplated this issue while trying to build a flex grid model which can fallback to a tables + table-cell model for older browsers. And Borders for column gutters seemed to me the best appropriate choice. i.e. Table-cells don't have margins.
e.g.
.column{
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 10px solid transparent;
}
Also note that you need min-width: 50px; for flexbox. The flex model will not handle fixed sizes unless you do flex: none; on the particular child element you want as fixed and therefore excluded from being "flexi". http://jsfiddle.net/GLpUp/4/
But all columns together with flex:none; is no longer a flex model.
Here is something closer to a flex model: http://jsfiddle.net/GLpUp/5/
So you can actually use margins normally if you don't need the table-cell fallback for older browsers. http://jsfiddle.net/GLpUp/3/
Setting background-clip: padding-box; will be necessary when using a background, as otherwise the background will flow into the transparent border area.
This solution will work for all cases even if there are multiple rows or any number of elements. But the count of the section should be same you want 4 in first row and 3 is second row it won't work that way the space for the 4th content will be blank the container won't fill.
We are using display: grid; and its properties.
#box {
display: grid;
width: 100px;
grid-gap: 5px;
/* Space between items */
grid-template-columns: repeat(4,1fr);
/* Decide the number of columns(4) and size(1fr | 1 Fraction | you can use pixels and other values also) */
}
.item {
background: gray;
width: 100%;
/* width is not necessary only added this to understand that width works as 100% to the grid template allocated space **DEFAULT WIDTH WILL BE 100%** */
height: 50px;
}
<div id='box'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
The Downside of this method is in Mobile Opera Mini will not be supported and in PC this works only after IE10.
Note for complete browser compatability including IE11 please use Autoprefixer
OLD ANSWER
Don't think of it as an old solution, it's still one of the best if you only want single row of elements and it will work with all the browsers.
This method is used by CSS sibling combination, so you can manipulate it many other ways also, but if your combination is wrong it may cause issues also.
.item+.item{
margin-left: 5px;
}
The below code will do the trick. In this method, there is no need to give margin: 0 -5px; to the #box wrapper.
A working sample for you:
#box {
display: flex;
width: 100px;
}
.item {
background: gray;
width: 22px;
height: 50px;
}
.item+.item{
margin-left: 5px;
}
<div id='box'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
Let's say if you want to set 10px space between the items, you can just set .item {margin-right:10px;} for all, and reset it on the last one .item:last-child {margin-right:0;}
You can also use general sibling ~ or next + sibling selector to set left margin on the items excluding the first one .item ~ .item {margin-left:10px;} or use .item:not(:last-child) {margin-right: 10px;}
Flexbox is so clever that it automatically recalculates and equally distributes the grid.
body {
margin: 0;
}
.container {
display: flex;
}
.item {
flex: 1;
background: gray;
height: 50px;
}
.item:not(:last-child) {
margin-right: 10px;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
If you want to allow flex wrap, see the following example.
body {
margin: 0;
}
.container {
display: flex;
flex-wrap: wrap;
margin-left: -10px;
}
.item {
flex: 0 0 calc(50% - 10px);
background: gray;
height: 50px;
margin: 0 0 10px 10px;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Update: gap for flexbox is now supported in all modern browsers (Edge/Chrome/Opera/Samsung Internet/Safari/Firefox)
Eventually they will add the gap property to flexbox. Until then you could use CSS grid instead which already has the gap property, and just have a single row. Nicer than dealing with margins.
I have found a solution that is based on the general sibling selector, ~, and allows infinite nesting.
See this code pen for a working example
Basically, inside of column containers, every child that is preceded by another child gets a top margin. Likewise, inside every row container, every child that is preceded by another gets a left margin.
.box {
display: flex;
flex-grow: 1;
flex-shrink: 1;
}
.box.columns {
flex-direction: row;
}
.box.columns>.box~.box {
margin-left: 5px;
}
.box.rows {
flex-direction: column;
}
.box.rows>.box~.box {
margin-top: 5px;
}
<div class="box columns">
<div class="box" style="background-color: red;"></div>
<div class="box rows">
<div class="box rows">
<div class="box" style="background-color: blue;"></div>
<div class="box" style="background-color: orange;"></div>
<div class="box columns">
<div class="box" style="background-color: yellow;"></div>
<div class="box" style="background-color: pink;"></div>
</div>
</div>
<div class="box" style="background-color: green;"></div>
</div>
</div>
According to #ChromeDevSummit there's an implementation of the gap property for Flexbox in Firefox and Chromium-based browsers.
Here's a Live Demo
Moving on from sawa's answer, here's a slightly improved version that allows you to set a fixed spacing between the items without the surrounding margin.
http://jsfiddle.net/chris00/s52wmgtq/49/
Also included is the Safari "-webkit-flex" version.
.outer1 {
background-color: orange;
padding: 10px;
}
.outer0 {
background-color: green;
overflow: hidden;
}
.container
{
display: flex;
display: -webkit-flex;
flex-wrap: wrap;
-webkit-flex-wrap: wrap;
background-color: rgba(0, 0, 255, 0.5);
margin-left: -10px;
margin-top: -10px;
}
.item
{
flex-grow: 1;
-webkit-flex-grow: 1;
background-color: rgba(255, 0, 0, 0.5);
width: 100px;
padding: 10px;
margin-left: 10px;
margin-top: 10px;
text-align: center;
color: white;
}
<div class="outer1">
<div class="outer0">
<div class="container">
<div class="item">text</div>
<div class="item">text</div>
<div class="item">text</div>
<div class="item">text</div>
<div class="item">text</div>
<div class="item">text</div>
</div>
</div>
</div>
I have used this for wrapped and fixed width columns. The key here is calc()
SCSS sample
$gap: 10px;
dl {
display: flex;
flex-wrap: wrap;
padding: $gap/2;
dt, dd {
margin: $gap/2;}
dt { // full width, acts as header
flex: 0 0 calc(100% - #{$gap});}
dd { // default grid: four columns
flex: 0 0 calc(25% - #{$gap});}
.half { // hall width columns
flex: 0 0 calc(50% - #{$gap});}
}
Full Codepen sample
A flex container with -x (negative) margin and flex items with x (positive) margin or padding both lead to the desired visual result: Flex items have a fixed gap of 2x only between each other.
It appears to be simply a matter of preference, whether to use margin or padding on the flex items.
In this example, the flex items are scaled dynamically in order to preserve the fixed gap:
.flex-container {
margin: 0 -5px;
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.flex-item {
margin: 0 5px; // Alternatively: padding: 0 5px;
flex: 1 0 auto;
}
Using Flexbox in my solution I've used the justify-content property for the parent element (container) and I've specified the margins inside the flex-basis property of the items.
Check the code snippet below:
.container {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
margin-bottom: 10px;
}
.item {
height: 50px;
display: flex;
justify-content: center;
align-items: center;
background-color: #999;
}
.item-1-4 {
flex-basis: calc(25% - 10px);
}
.item-1-3 {
flex-basis: calc(33.33333% - 10px);
}
.item-1-2 {
flex-basis: calc(50% - 10px);
}
<div class="container">
<div class="item item-1-4">1</div>
<div class="item item-1-4">2</div>
<div class="item item-1-4">3</div>
<div class="item item-1-4">4</div>
</div>
<div class="container">
<div class="item item-1-3">1</div>
<div class="item item-1-3">2</div>
<div class="item item-1-3">3</div>
</div>
<div class="container">
<div class="item item-1-2">1</div>
<div class="item item-1-2">2</div>
</div>
With flexbox, creating gutters is a pain, especially when wrapping is involved.
You need to use negative margins (as shown in the question):
#box {
display: flex;
width: 100px;
margin: 0 -5px;
}
... or alter the HTML (as shown in another answer):
<div class='flex-wrapper'>
<div class='flex'>
<div class='box'></div>
<div class='box'></div>
...
</div>
</div>
... or something else.
In any case, you need an ugly hack to make it work because flexbox doesn't provide a "flex-gap" feature
(at least for now).
The issue of gutters, however, is simple and easy with CSS Grid Layout.
The Grid spec provides properties that create space between grid items, while ignoring the space between items and the container. These properties are:
grid-column-gap
grid-row-gap
grid-gap (the shorthand for both properties above)
Recently, the spec has been updated to conform with the CSS Box Alignment Module, which provides a set of alignment properties for use across all box models. So the properties are now:
column-gap
row-gap
gap (shorthand)
However, not all Grid-supporting browsers support the newer properties, so I'll use the original versions in the demo below.
Also, if spacing is needed between items and the container, padding on the container works just fine (see the third example in the demo below).
From the spec:
10.1. Gutters: the row-gap, column-gap, and gap
properties
The row-gap and column-gap properties (and their gap shorthand),
when specified on a grid container, define the gutters between grid
rows and grid columns. Their syntax is defined in CSS Box Alignment 3
ยง8 Gaps Between Boxes.
The effect of these properties is as though the affected grid lines
acquired thickness: the grid track between two grid lines is the space
between the gutters that represent them.
.box {
display: inline-grid;
grid-auto-rows: 50px;
grid-template-columns: repeat(4, 50px);
border: 1px solid black;
}
.one {
grid-column-gap: 5px;
}
.two {
grid-column-gap: 10px;
grid-row-gap: 10px;
}
.three {
grid-gap: 10px;
padding: 10px;
}
.item {
background: lightgray;
}
<div class='box one'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
<hr>
<div class='box two'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
<hr>
<div class='box three'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
More information:
Browser Support for CSS Grid
Make it easier to define margins that only apply between flex-items (discussion)
Spacing between flexbox items
Why not do it like this:
.item + .item {
margin-left: 5px;
}
This uses the adjacent sibling selector, to give all .item elements, except the first one a margin-left. Thanks to flexbox, this even results in equally wide elements. This could also be done with vertically positioned elements and margin-top, of course.
Here's my solution, that doesn't require setting any classes on the child elements:
.flex-inline-row {
display: inline-flex;
flex-direction: row;
}
.flex-inline-row.flex-spacing-4px > :not(:last-child) {
margin-right: 4px;
}
Usage:
<div class="flex-inline-row flex-spacing-4px">
<span>Testing</span>
<span>123</span>
</div>
The same technique can be used for normal flex rows and columns in addition to the inline example given above, and extended with classes for spacing other than 4px.
I often use the + operator for such cases
#box {
display: flex;
width: 100px;
}
.item {
background: gray;
width: 50px;
height: 50px;
}
.item + .item {
margin-left: 5px;
}
<div id='box'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
You could use the new property gap. I copy paste the explanation I found in this article, as well as more information
CSS grid layout has had gap (previously grid-gap) for some time. By specifying the internal spacing of a containing element rather than the spacing around child elements, gap solves many common layout issues. For example, with gap, you don't have to worry about margins on child elements causing unwanted whitespace around the edges of a containing element:
Unfortunately right now, only FireFox supports gap in flex layouts.
#use postcss-preset-env {
stage: 0;
browsers: last 2 versions
}
section {
width: 30vw;
display: grid;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(12ch, 1fr));
&[flex] {
display: flex;
flex-wrap: wrap;
}
margin-bottom: 3rem;
}
.tag {
color: white;
background: hsl(265 100% 47%);
padding: .5rem 1rem;
border-radius: 1rem;
}
button {
display: inline-flex;
place-items: center;
gap: .5rem;
background: hsl(265 100% 47%);
border: 1px solid hsl(265 100% 67%);
color: white;
padding: 1rem 2rem;
border-radius: 1rem;
font-size: 1.25rem;
}
body {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
<section>
<h1>Grid</h1>
<div class="tag">Awesome</div>
<div class="tag">Coo</div>
<div class="tag">Rad</div>
<div class="tag">Math</div>
</section>
<br>
<section flex>
<h1>Flex</h1>
<div class="tag">Awesome</div>
<div class="tag">Coo</div>
<div class="tag">Rad</div>
<div class="tag">Math</div>
</section>
I find the easiest way of doing this is with percentages and just allowing the margin to tally up your width
This means you end up with something like this if you where using your example
#box {
display: flex;
}
.item {
flex: 1 1 23%;
margin: 0 1%;
}
Does mean your values are based on the width though which might not be good for everybody.
Here's a grid of card UI elements with spacing completed using flexible box:
I was frustrated with manually spacing the cards by manipulating padding and margins with iffy results. So here's the combinations of CSS attributes I've found very effective:
.card-container {
width: 100%;
height: 900px;
overflow-y: scroll;
max-width: inherit;
background-color: #ffffff;
/*Here's the relevant flexbox stuff*/
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
flex-wrap: wrap;
}
/*Supplementary styles for .card element*/
.card {
width: 120px;
height: 120px;
background-color: #ffeb3b;
border-radius: 3px;
margin: 20px 10px 20px 10px;
}
<section class="card-container">
<div class="card">
</div>
<div class="card">
</div>
<div class="card">
</div>
<div class="card">
</div>
</section>
Hope this helps folks, present and future.
Columnify - A solo class for N columns
Flexbox and SCSS
.columnify {
display: flex;
> * {
flex: 1;
&:not(:first-child) {
margin-left: 2rem;
}
}
}
Flexbox and CSS
.columnify {
display: flex;
}
.columnify > * {
flex: 1;
}
.columnify > *:not(:first-child) {
margin-left: 2rem;
}
<div class="columnify">
<div style="display: inline-block; height: 20px; background-color: blue;"></div>
<div style="display: inline-block; height: 20px; background-color: blue"></div>
<div style="display: inline-block; height: 20px; background-color: blue"></div>
</div>
Play with it on JSFiddle.
#box {
display: flex;
width: 100px;
}
.item {
background: gray;
width: 50px;
height: 50px;
}
/* u mean utility */
.u-gap-10 > *:not(:last-child) {
margin-right: 10px;
}
<div id='box' class="u-gap-10">
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
Just use .item + .item in selector to match from second .item
#box {
display: inline-flex;
margin: 0 -5px;
}
.item {
background: gray;
width: 10px;
height: 50px;
}
#box .item + .item {
margin-left: 10px;
}
<div id='box'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
I found a hack because i really need this my self.
/* grid */
.container {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.container::after, /* this makes sure odd element goes left and not space between */
.item {
content:"";
width: calc(33.3333% - 20px);
margin-bottom: 40px;
}
/* extra styling - not important */
.item {
height: 100px;
background: #787878;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Here's a post grid with nice flex grow categories also.
I think you'd like it.
See Codepen
Assuming:
You want 4 column grid layout with wrapping
The number of items is not necessarily a multiple of 4
Set a left margin on every item except 1st, 5th, 9th item and so on; and set fixed width on each item. If the left margin is 10px then each row will have 30px margin between 4 items, the percentage width of item can be calculated as follows:
100% / 4 - horizontal-border - horizontal-padding - left-margin * (4 - 1) / 4
This is a decent workaround for issues involving last row of flexbox.
.flex {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 1em 0;
background-color: peachpuff;
}
.item {
margin-left: 10px;
border: 1px solid;
padding: 10px;
width: calc(100% / 4 - 2px - 20px - 10px * (4 - 1) / 4);
background-color: papayawhip;
}
.item:nth-child(4n + 1) {
margin-left: 0;
}
.item:nth-child(n + 5) {
margin-top: 10px;
}
<div class="flex">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
</div>
<div class="flex">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
<div class="flex">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
</div>
There is indeed a nice, tidy, CSS-only way to do this (that one may consider "better").
Of all the answers posted here, I only found one that uses calc() successfully (by Dariusz Sikorski). But when posed with: "but it fails if there are only 2 items in the last row" there was no solution expanded.
This solution addresses the OP's question with an alternative to negative margins and addresses the problem posed to Dariusz.
notes:
This example only demonstrates a 3-column layout
It uses calc() to let the browser do math the way it wants --
100%/3 (although 33.3333% should work just as well), and
(1em/3)*2 (although .66em should also work well).
It uses ::after to pad the last row if there are fewer elements than columns
.flex-container {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.flex-container:after {
content: "";
}
.flex-container > div,
.flex-container:after {
box-sizing: border-box;
width: calc((100%/3) - ((1em/3)*2));
}
.flex-container > :nth-child(n + 4) {
margin-top: 1em;
}
/* the following is just to visualize the items */
.flex-container > div,
.flex-container:after {
font-size: 2em;
}
.flex-container {
margin-bottom:4em;
}
.flex-container > div {
text-align: center;
background-color: #aaa;
padding: 1em;
}
.flex-container:after {
border: 1px dashed red;
}
<h2>Example 1 (2 elements)</h2>
<div class="flex-container">
<div>1</div>
<div>2</div>
</div>
<h2>Example 2 (3 elements)</h2>
<div class="flex-container">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
Also at https://codepen.io/anon/pen/rqWagE
You could use the following equation
.container {
max-width: 960px;
margin: 0 auto;
padding: 4rem 0;
}
.flex {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
}
.flex:after {
content: "";
max-width: calc(100% * var(--col) / 12 - var(--gap));
width: 100%;
}
#media (max-width: 960px) {
.flex:after {
max-width: calc(100% * var(--colTablet) / 12 - var(--gap));
}
}
#media (max-width: 680px) {
.flex:after {
max-width: calc(100% * var(--colMobile) / 12 - var(--gap));
}
}
.flex .item {
max-width: calc(100% * var(--col) / 12 - var(--gap));
width: 100%;
}
#media (max-width: 960px) {
.flex .item {
max-width: calc(100% * var(--colTablet) / 12 - var(--gap));
margin-bottom: 1rem;
}
.flex .item:last-child {
margin-bottom: unset;
}
}
#media (max-width: 680px) {
.flex .item {
max-width: calc(100% * var(--colMobile) / 12);
}
}
.flex .item .card {
background: #eee;
text-align: center;
padding: 2rem;
}
<div class="flex container" style="--col: 3; --colTablet: 6; --colMobile: 12; --gap: 2%">
<div class="item" style="--col: 3; --colTablet: 6; --colMobile: 12; --gap: 2%">
<div class="card">
<h2>Hello world</h2>
</div>
</div>
<div class="item" style="--col: 3; --colTablet: 6; --colMobile: 12; --gap: 2%">
<div class="card">
<h2>Hello world</h2>
</div>
</div>
<div class="item" style="--col: 3; --colTablet: 6; --colMobile: 12; --gap: 2%">
<div class="card">
<h2>Hello world</h2>
</div>
</div>
</div>
I came across the same issue earlier, then stumbled upon the answer for this. Hope it will help others for future reference.
long answer short, add a border to your child flex-items.
then you can specify margins between flex-items to whatever you like.
In the snippet, i use black for illustration purposes, you can use 'transparent' if you like.
#box {
display: flex;
width: 100px;
/* margin: 0 -5px; *remove this*/
}
.item {
background: gray;
width: 50px;
height: 50px;
/* margin: 0 5px; *remove this*/
border: 1px solid black; /* add this */
}
.item.special{ margin: 0 10px; }
<div id='box'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item special'></div>
</div>

Flex box isn't filling remaining space when using flex-grow 1

I am trying to fill the remaining space of a containing flex box with the green div. I want the top flex row (blue) to only be the height of its contents and then the row below (green) to fill the rest. For some reason it just seems to split the flex rows evenly down the div. I have read a few questions on here already which all say to make sure the containing div has its height set to 100%. I have set the containing div height to 200px as this is my desired height, but I have also tried adding another container within this to 100% to no avail. I've also made sure to set the flex-grow property on the second row to 1. Every time I think I'm beginning to understand flex it throws another curve ball and it's driving me up the wall. Please help! Thank you.
P.S. for some reason the HTML code snippet below refuses to include the first line of my html but it is contained in the following div: <div class="rmCtrlList_item"
.rmCtrlList_item {
width: 80vw;
margin: 3vw 8.5vw;
height: 200px;
background-color: $primary-color;
border-radius: 10px;
padding: 5px;
display: flex;
flex-flow: row;
flex-wrap: wrap;
// ROWS
&_row {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
#row-1 {
//max-height: 20px;
background-color: blue;
}
#row-2 {
flex-grow: 1;
align-items: center;
justify-content: center;
background-color: green;
}
// COLUMNS
&_col {
text-align: left;
flex-direction: column;
}
#col-1b {
flex-grow: 1;
}
}
<div class="rmCtrlList_item">
<div class="rmCtrlList_item_row" id="row-1">
<div class="rmCtrlList_item_col" id="col-1a">
<i class="icon__panel-2 fas fa-lightbulb"></i>
</div>
<div class="rmCtrlList_item_col" id="col-1b">
<a href="lights.html">
<h1 class="panel__title">Lights</h1>
</a>
</div>
<div class="rmCtrlList_item_col" id="col-1c">
<i class="icon__enlarge fas fa-plus-circle"></i>
</div>
</div>
<div class="rmCtrlList_item_row" id="row-2">
div to fill remaining space
</div>
</div>
how about to use flex-direction and below code what I used? green will fill ramaining space automatically, if you use its height's 100%
.container{
display: flex;
flex-direction: column;
width: 200px;
height: 300px;
border: 1px solid black;
}
.blue{
width: 100%;
height: 90px; /*change only blue's height size, green will be filled automatically*/
background: blue;
}
.green{
width: 100%;
height: 100%;
background: green;
}
<div class="container">
<div class="blue"></div>
<div class="green"></div>
</div>

Changing the size of individual element in flexbox

How can I stretch the items inside a div to fill the area, and is it possible to have the items in different sizes without having to modify individually using :nth-child(x). For instance: first, third and fifth item to be twice as big as second and fourth item?
.my_class_a {
display: flex;
align-items: center;
flex-wrap: wrap;
}
<div class="my_class_a">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c</div>
<div class="item">d</div>
<div class="item">e</div>
</div>
I do apologize because I don't know how to format in fiddle way.
How can I stretch the items inside a div to fill the area...
Use the flex-grow property.
and is it possible to have the items in different sizes without having to modify individually using :nth-child(x).
How is the browser supposed to know what you want if you don't define the behavior?
For instance: first, third and fifth item to be twice as big as second and fourth item?
In this case, you can use the even and odd functions of the nth-child() pseudo class.
.my_class_a {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.item:nth-child(odd) {
flex-grow: 2;
background-color: lightgreen; /* for demo only */
}
.item:nth-child(even) {
flex-grow: 1;
background-color: orange; /* for demo only */
}
/* for aligning item content */
.item {
display: flex;
align-items: center;
justify-content: center;
}
<div class="my_class_a">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c</div>
<div class="item">d</div>
<div class="item">e</div>
</div>
In general you can use flex-grow: 1; to allow flex items to become larger. (Note that i defined a width for the container, otherwise they won't grow)
Concerning your wish about the 2nd, 4th etc. item: You need to define * somewhere* which items should grow and which not, so you you need at least some kind of selector for them.
.my_class_a {
display: flex;
flex-wrap: wrap;
width: 100%;
align-items: center;
}
.item {
border: 1px solid #333;
flex-grow: 1;
padding: 12px;
text-align: center;
}
<div class="my_class_a">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c<br>c</div>
<div class="item">d</div>
<div class="item">e</div>
</div>
P.S.: To create a snippet (the "fiddle-line" code example, just click the 7th symbol in the toolbar of the answer window)
You can use the flex style declaration - it's a shorthand for:
flex-grow | flex-shrink | flex-basis
where flex-basis is the initial width of the flexbox child and flex-grow and flex-shrink determine how quickly the flexbox child will grow or shrink relative to its siblings.
For instance:
an element with flex: 2 2 100px starts with a width of 100px and will grow or shrink twice as fast as flex: 1 1 50px which starts with a width of 50px.
Working Example:
.my_class_a {
display: flex;
width: 100%;
align-items: center;
}
.item {
color: rgb(255, 255, 255);
text-align: center;
font-weight: bold;
}
.item-a,
.item-c,
.item-e {
flex: 2 2 100px;
background-color: rgb(255, 0, 0);
}
.item-b,
.item-d {
flex: 1 1 50px;
background-color: rgb(0, 0, 0);
}
<div class="my_class_a">
<div class="item item-a">a</div>
<div class="item item-b">b</div>
<div class="item item-c">c</div>
<div class="item item-d">d</div>
<div class="item item-e">e</div>
</div>

Aligning the last div to the bottom of a flexbox

Scenario :
I'm creating a pricing comparison table and am having difficulties aligning the last div, card-vat-fee, to the bottom of the container.
I need to do this because the tiers have longer running lists than
one another, causing the last div isn't aligned with the bottom of
the container.
How can I get the last div to align to the bottom of the flexbox?
Tried Case :
Of course, if I set a min-height: 320px; on the card-vat-fee class it will align the div to the bottom, however this isn't a responsive solution and I feel like there is a better approach that uses flex properties. Moreover, setting the card-vat-fee div to flex-grow, flex: 1 1 auto, produces an unideal solution.
Code :
<div class='pricing__tier'>
<div class='uni-card-header'>
</div>
<div class='uni-card-body'>
<div class='uni-row-on'>
</div>
<div class='uni-row-off'>
</div>
<div class='uni-row-on card-vat-fee'>
<div class='vat-fee-text'>
Credit card fees and VAT apply. See below for details.
</div>
</div>
</div>
</div>
<style>
.pricing__tier {
padding: 0;
text-align: center;
display: flex;
flex-direction: column;
width: 0%;
flex: 1;
}
.uni-card-body {
display: flex;
flex-direction: column;
}
</style>
Pricing Tier
Please Suggest.
Thanks in advance
Use margin-top:auto on the last div.
.pricing__tier {
padding: 0;
text-align: center;
display: flex;
flex-direction: column;
width: 25%;
flex: 1;
height: 200px; /* for demo purposes */
border: 1px solid grey;
}
.uni-card-body {
display: flex;
flex-direction: column;
flex: 1;
}
.card-vat-fee {
margin-top: auto; /* push to bottom */
background: green;
}
<div class='pricing__tier'>
<div class='uni-card-header'>
</div>
<div class='uni-card-body'>
<div class='uni-row-on'>
</div>
<div class='uni-row-off'>
</div>
<div class='uni-row-on card-vat-fee'>
<div class='vat-fee-text'>
Credit card fees and VAT apply. See below for details.
</div>
</div>
</div>
</div>
plaesa try this one :
.uni-card-body {
display: flex;
flex-direction: column;
width: 'for example' 700px;
}
.uni-row-on.card-vat-fee{
align-self: flex-end;
}
Ihope this will help you!
.uni-card-body {
display: flex;
flex-flow: row wrap;
justify-content: center;
background: yellow;
height: 90vh;
}
.uni-row-on.card-vat-fee {
align-self: flex-end;
background: green;
}
<div class='pricing__tier'>
<div class='uni-card-header'>
</div>
<div class='uni-card-body'>
<div class='uni-row-on'>
</div>
<div class='uni-row-off'>
</div>
<div class='uni-row-on card-vat-fee'>
<div class='vat-fee-text'>
Credit card fees and VAT apply. See below for details.
</div>
</div>
</div>
</div>
I've illustrated the thing in the snippet, it'll help.
Note: Content justification, background and height are for demonstration and not necessary.
1- set the parent div relative position without top & left & right &
bottom property
2- set the last div position absolute with bottom:0;right:0;left:0;height:36px;
<style>
.pricing__tier {
position:relative;
padding: 0;
text-align: center;
display: flex;
flex-direction: column;
width: 0%;
flex: 1;
}
.pricing__tier>.vat-fee-text {
position:absolute;
bottom:0;
right:0;
left:0;
height:36px;
}
</style>

Prevent a child element from overflowing its parent in flexbox [duplicate]

This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Closed 5 years ago.
I'm working on a web app that shows a large grid of cards, the height of which is inherently variable.
In the interests of aesthetics, we were using jQuery's .matchHeight() to equalise the height of cards within each row.
The performance of that didn't scale well, so today I've been migrating to a flex-box based solution which is so much faster.
However, I've lost a behaviour - the content of the card header should be truncated with an ellipsis if it won't fit.
Goals:
3 columns
Column widths vary to fill parent
Constant spacing between columns
Heights equalised within a row
How do I arrange for the container size to be respected and the text-overflow: ellipsis; and white-space: nowrap; to be honoured?
(No jQuery tag as we're moving away from that)
My solution in it's current form, which achieves all of my goals apart from the truncation:
https://codepen.io/anon/pen/QvqZYY
#container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start; /* Bias cards to stack from left edge */
align-items: stretch; /* Within a row, all cards the same height */
border: thin solid gray;
}
.card-wrapper {
width: 33.33%;
display: flex;
background: #e0e0ff;
}
.card {
flex-grow: 1;
margin: 7px;
display: flex;
flex-direction: column;
border: thin solid gray;
background: #e0ffff;
}
.card div {
border: thin solid gray;
}
.card div:nth-child(1) {
white-space: nowrap;
text-overflow: ellipsis;
}
.card div:nth-child(2) {
flex-grow: 2;
}
<div id="container">
<div class="card-wrapper">
<div class="card">
<div>Title</div>
<div>Multiline<br/>Body</div>
<div>Footer</div>
</div>
</div>
<div class="card-wrapper"><div class="card"><div>Really long rambling title that pushes beyond the bounds of the container, unless your screen is really, really wide</div><div>Body</div><div>Footer</div></div></div>
<div class="card-wrapper"><div class="card"><div>Title</div><div>Body</div><div>Footer</div></div></div>
<div class="card-wrapper"><div class="card"><div>Title</div><div>Body</div><div>Footer</div></div></div>
<div class="card-wrapper"><div class="card"><div>Title</div><div>Body</div><div>Footer</div></div></div>
</div>
An initial setting on flex items is min-width: auto. This means that a flex item, by default, cannot be smaller than the size of its content.
Therefore, text-overflow: ellipsis cannot work because a flex item will simply expand, rather than permit an overflow. (Scroll bars will not render either, for the same reason.)
To override this behavior, use min-width: 0 or overflow: hidden. More details.
#container {
display: flex;
flex-wrap: wrap;
border: thin solid gray;
}
.card-wrapper {
width: 33.33%;
display: flex;
background: #e0e0ff;
}
.card {
flex-grow: 1;
margin: 7px;
display: flex;
flex-direction: column;
border: thin solid gray;
background: #e0ffff;
overflow: hidden; /* NEW */
}
.card div {
border: thin solid gray;
}
.card div:nth-child(1) {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden; /* NEW */
}
.card div:nth-child(2) {
flex-grow: 2;
}
<div id="container">
<div class="card-wrapper">
<div class="card">
<div>Title</div>
<div>Multiline<br/>Body</div>
<div>Footer</div>
</div>
</div>
<div class="card-wrapper">
<div class="card">
<div>Really long rambling title that pushes beyond the bounds of the container, unless your screen is really, really wide</div>
<div>Body</div>
<div>Footer</div>
</div>
</div>
<div class="card-wrapper">
<div class="card">
<div>Title</div>
<div>Body</div>
<div>Footer</div>
</div>
</div>
<div class="card-wrapper">
<div class="card">
<div>Title</div>
<div>Body</div>
<div>Footer</div>
</div>
</div>
<div class="card-wrapper">
<div class="card">
<div>Title</div>
<div>Body</div>
<div>Footer</div>
</div>
</div>
</div>