Flex-Basis for Wrapping Columns - css

I have a pretty basic grid setup in flex, but I recently came across an oversight I made.
I have columns that have a margin-right: 3em and flex-basis: calc(33% - 3em).
My problem is that the 4th and 5th of these don't line up until there is a full "row" of 3.
Any insights as to why this is happening? I imagine I may be over-complicating things as per usual.
section {
width: 1170px;
margin: 0 auto;
padding: 4em;
background-color: lightgray;
}
.flex {
display: flex;
}
.wrap {
flex-wrap: wrap;
}
.column {
flex: 1;
flex-direction: column;
margin-right: 3em;
}
.column:last-child {
margin-right: 0;
}
.three {
max-width: 33%;
flex-basis: calc(33% - 3em);
}
.three:nth-child(3n) {
margin-right: 0;
}
.debug {
margin-bottom: 3em;
background-color: #ebf5fb;
height: 3em;
border: 1px dashed red;
text-align: center;
}
<section>
<div class="flex wrap">
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
</div>
</section>
Codepen

Since you use flex: 1, it will make the element take all available space, what's left after the flex-basis been retracted.
What stop the 2 last items from filling the entire row is the max-width, and since that its value is wider than the flex-basis, they will expand to it.
Either remove flex: 1 from column, or use the same calc for max-width as used for flex-basis
Stack snippet
section {
width: 1170px;
margin: 0 auto;
padding: 4em;
background-color: lightgray;
}
.flex {
display: flex;
}
.wrap {
flex-wrap: wrap;
}
.column {
flex: 1;
flex-direction: column;
margin-right: 3em;
}
.column:last-child {
margin-right: 0;
}
.three {
max-width: calc(33% - 3em); /* changed */
flex-basis: calc(33% - 3em);
}
.three:nth-child(3n) {
margin-right: 0;
}
.debug {
margin-bottom: 3em;
background-color: #ebf5fb;
height: 3em;
border: 1px dashed red;
text-align: center;
}
<section>
<div class="flex wrap">
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
</div>
</section>
Updated based on a comment
If to also make the items spread equally inside its parent, one need to divide the sum of the actual margin/gutter/gap space with the amount of items.
So in this case it would be (2 gaps * 3em) / 3 items = 2em
Also, one need the closest possible to a 1/3, which can be either e.g. 33.33333% or (100% / 3)
Stack snippet
section {
width: 1170px;
margin: 0 auto;
padding: 4em;
background-color: lightgray;
}
.flex {
display: flex;
}
.wrap {
flex-wrap: wrap;
}
.column {
flex: 1;
flex-direction: column;
margin-right: 3em;
}
.column:last-child {
margin-right: 0;
}
.three {
max-width: calc(33.33333% - 2em); /* changed */
flex-basis: calc(33.33333% - 2em); /* changed */
}
.three:nth-child(3n) {
margin-right: 0;
}
.debug {
margin-bottom: 3em;
background-color: #ebf5fb;
height: 3em;
border: 1px dashed red;
box-sizing: border-box; /* added */
text-align: center;
}
.debug2 {
border: 1px dashed red; /* added */
box-sizing: border-box; /* added */
}
<section>
<div class="flex wrap debug2">
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
<div class="column three debug">3 Columns</div>
</div>
</section>

Thank you LGson for pointing me in the right direction.
My math was incorrect.
I needed to take 100% - the total margins in the row.
Instead of flex-basis: calc(33% - 3em); it needed to be flex-basis: calc( (100% - 6em) / 3);
Updated Snippet
*,
::before,
::after {
background-repeat: no-repeat; /* 1 */
box-sizing: inherit; /* 2 */
}
html {
box-sizing: border-box; /* 1 */
cursor: default; /* 2 */
-ms-text-size-adjust: 100%; /* 3 */
-webkit-text-size-adjust: 100%; /* 3 */
}
section {
width: 1170px;
margin: 0 auto;
padding: 4em;
background-color: lightgray;
}
.flex {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.wrap {
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
.column {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
margin-right: 3em;
/*overflow: hidden;*/
}
.column:last-child {
margin-right: 0;
}
.three {
max-width: calc( (100% - 6em) / 3);
-ms-flex-preferred-size: calc( (100% - 6em) / 3);
flex-basis: calc( (100% - 6em) / 3);
}
.three:nth-child(3n) {
margin-right: 0;
}
.debug {
background-color: #EBF5FB;
margin-top: 1em;
padding: .75em;
text-align: center;
border: 1px dashed #E8DAEF;
}
<section>
<h2>Layout for 2 Dimensions</h2>
<h3>Specific Widths (or not)</h3>
<div class="flex wrap">
<div class="column three debug">1/3 Columns</div>
<div class="column three debug">1/3 Columns</div>
<div class="column three debug">1/3 Columns</div>
<div class="column three debug">1/3 Columns</div>
<div class="column three debug">1/3 Columns</div>
</div>
</section>

Related

CSS Flex item spanning two rows without fixed height

I am trying to create a flex container layout whereby one of the flex items should span two rows. See image below for a better explanation:
Here is my markup:
<div class="container">
<div class="item item-1">ITEM 1</div>
<div class="item item-2">ITEM 2</div>
<div class="item item-3">ITEM 3</div>
</div>
I cannot seem to achieve this, I have tried using flex-wrap and different combinations of the flex property.
I was able to achieve this by putting ITEM 1 & ITEM 2 in a separate <div>, but this presents a problem on a smaller screen, whereby ITEM 3 needs to appear BETWEEN ITEM 1 & ITEM 2. So I would rather keep the markup as is and use the order property to move things around as necessary.
You can use display: contents on your extra div to achieve what you want:
* {
box-sizing: border-box;
}
.container {
display: flex;
width: 100%;
}
.holder {
width: 67%;
}
.item {
border: 1px solid black;
}
.item-1 {
margin-bottom: 40px;
}
.item-3 {
width: 33%;
}
#media screen and (max-width: 700px) {
.container {
flex-direction: column;
}
.item {
margin-bottom: 20px;
}
.item-1 {
order: 1;
}
.item-2 {
order: 3;
}
.item-3 {
order: 2;
width: 100%;
}
.holder {
width: 100%;
display: contents;
}
}
<div class="container">
<div class="holder">
<div class="item item-1">ITEM 1</div>
<div class="item item-2">ITEM 2</div>
</div>
<div class="item item-3">ITEM 3</div>
</div>
You can't achieve it using flexbox. Instead, you should have two parents which are better.
Use Css-grid. Actually, css-grid is the best option in this case.
Flex-Box
* {
color: #fff;
}
.flex {
display: flex;
justify-content: center;
align-items: center;
}
.child {
border-radius: 10px;
}
.container {
display: flex;
width: 500px;
height: 200px;
border: 1px solid #ff0000;
}
.container .first-item {
flex-direction: column;
justify-content: space-between;
align-items: start;
width: 50%;
height: 100%;
margin-right: 10px;
}
.first-item .child {
width: 100%;
height: 50%;
background-color: blue;
}
.first-item .child:first-child {
margin-bottom: 10px;
}
.container .second-item {
width: 50%;
height: 100%;
}
.second-item .child {
width: 100%;
height: 100%;
background-color: blue;
}
<div class="container">
<div class="first-item flex">
<div class="child flex">Item 1</div>
<div class="child flex">Item 2</div>
</div>
<div class="second-item flex">
<div class="child flex">Item 3</div>
</div>
</div>
Grid
.flex {
display: flex;
justify-content: center;
align-items: center;
}
.child {
background-color: blue;
border-radius: 10px;
}
.container {
display: grid;
grid-template-columns: 1fr 10px 1fr;
grid-template-rows: 1fr 10px 1fr;
grid-template-areas: "c1 . c3"
". . c3"
"c2 . c3";
width: 500px;
height: 300px;
border: 1px solid red;
}
.container .child {
border: 1px solid blue;
}
.child1 {
grid-area: c1;
}
.child2 {
grid-area: c2;
}
.child3 {
grid-area: c3;
}
<div class="container">
<div class="child child1 flex">Item 1</div>
<div class="child child3 flex">Item 3</div>
<div class="child child2 flex">Item 2</div>
</div>
i dont know if its a good solution but
put two item3 codes one in the individual div (item1&2) and one outside then put the one in the div to display none in non-small screens and switch between them with mediaquery
#media (max-width: 40rem) {
.item3 {
display: none;
}
.mobile-item3{
display: block;
}
}

FlexBox - How to display one column 100% and two others 50%

Looking at the bellow code, I'm trying to have the 3 child columns as follow:
The first column should be 100% wide and above two other columns.
Two other columns should be bellow the first column and each 50% wide.
Like this:
.flex-container {
width: 80%;
min-height: 300px;
margin: 0 auto;
display: flex;
}
.flex-container .column {
padding: 10px;
background: #dbdfe5;
flex: 1;
}
.column.first {
background: blueviolet;
}
.column.third {
background: #b4bac0;
}
<div class="flex-container">
<div class="column first">Column 1</div>
<div class="column second">Column 2</div>
<div class="column third">Column 3</div>
</div>
But whatever I try it doesn't work that way.
Is it possible or I'm trying an impossible layout?
Flexbox version
You can use flex-wrap: wrap on the container to make children that overflow go below, and use flex-basis: 100% on the first child and flex-basis: 50% on the 2 others.
I have also added box-sizing: border-box on the children, to avoid border or padding count in the percentage.
.flex-container {
width: 80%;
min-height: 300px;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
}
.flex-container .column {
padding: 10px;
background: #dbdfe5;
box-sizing: border-box;
}
.column.first {
background: blueviolet;
flex-basis: 100%;
}
.column.second {
flex-basis: 50%;
}
.column.third {
background: #b4bac0;
flex-basis: 50%;
}
<div class="flex-container">
<div class="column first">Column 1</div>
<div class="column second">Column 2</div>
<div class="column third">Column 3</div>
</div>
Grid version
The grid version is even simpler, you only need display: grid on the container, and grid-column: 1 / 3 on the first child.
.flex-container {
width: 80%;
min-height: 300px;
margin: 0 auto;
display: grid;
}
.flex-container .column {
padding: 10px;
background: #dbdfe5;
}
.column.first {
background: blueviolet;
grid-column: 1 / 3;
}
.column.third {
background: #b4bac0;
}
<div class="flex-container">
<div class="column first">Column 1</div>
<div class="column second">Column 2</div>
<div class="column third">Column 3</div>
</div>

How to set two elements be next each other using flexbox

I'm trying to make my css with flexbox, so I followed some articles and tried to set my elements like this example:
the elements 1 & 2 are in another container
I'm trying to set the two elements (1 and 3) to be next each other as the second example (The first is what I have now and the other is what I'm trying to achieve.)
but I can't find a good way with the Flexbox since I set the container to flex-direction: column;
<div class="container">
<div class="sub-ctn">
<h5 class="1"><span>♦ </span>{{ text }}</h5>
<span class="2">{{ value }}</span>
<div class="3">
<h5>{{ text }}
</div>
</div>
</div>
CSS:
.container {
margin-right: 2.5%;
direction: rtl;
}
.sub-ctn {
display: flex;
flex-flow: row;
margin-top: 1%;
flex-direction: column;
}
.1 {
width: 100%;
direction: rtl;
text-align: right;
}
.2 {
float: right;
/* text-align: right; */
}
.3 {
margin-left: 1%;
display: flex;
flex-direction: column;
}
let me know if another information is needed
Don't use float and flex together. Flex alone will be much easier and better.
.cont{
display: flex;
width: 80%;
border: 1px solid black;
padding: 10px;
}
.left-cont{
height: 100%;
flex-grow: 1;
}
.right-cont{
flex-grow: 1;
display: flex;
flex-direction: column;
}
.item{
text-align: center;
border: 1px solid black;
margin: 3px;
}
<div class="cont">
<div class="left-cont">
<div class="item">3</div>
</div>
<div class="right-cont">
<div class="item">1</div>
<div class="item">2</div>
</div>
</div>

Flex centererd grid with dynamic number of columns [duplicate]

I have a simple flex-box layout with a container like:
.grid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
Now I want the items in the last row to be aligned with the other. justify-content: space-between; should be used because the width and height of the grid can be adjusted.
Currently it looks like
Here, I want the item in the bottom right to be in the "middle column". What is the simplest way to accomplish that? Here is a small jsfiddle that shows this behaviour.
.exposegrid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.exposetab {
width: 100px;
height: 66px;
background-color: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(0, 0, 0, 0.4);
border-radius: 5px;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
margin-bottom: 10px;
}
<div class="exposegrid">
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
</div>
Add a ::after which autofills the space. No need to pollute your HTML. Here is a codepen showing it: http://codepen.io/DanAndreasson/pen/ZQXLXj
.grid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.grid::after {
content: "";
flex: auto;
}
As other posters have mentioned - there's no clean way to left-align the last row with flexbox (at least as per the current spec)
However, for what it's worth: With the CSS Grid Layout Module this is surprisingly easy to produce:
Basically the relevant code boils down to this:
ul {
display: grid; /* 1 */
grid-template-columns: repeat(auto-fill, 100px); /* 2 */
grid-gap: 1rem; /* 3 */
justify-content: space-between; /* 4 */
}
1) Make the container element a grid container
2) Set the grid with auto columns of width 100px. (Note the use of auto-fill (as apposed to auto-fit - which (for a 1-row layout) collapses empty tracks to 0 - causing the items to expand to take up the remaining space. This would result in a justified 'space-between' layout when grid has only one row which in our case is not what we want. (check out this demo to see the difference between them)).
3) Set gaps/gutters for the grid rows and columns - here, since want a 'space-between' layout - the gap will actually be a minimum gap because it will grow as necessary.
4) Similar to flexbox.
ul {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
grid-gap: 1rem;
justify-content: space-between;
/* boring properties */
list-style: none;
background: wheat;
padding: 2rem;
width: 80vw;
margin: 0 auto;
}
li {
height: 50px;
border: 1px solid green;
}
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
Codepen Demo (Resize to see the effect)
One technique would be inserting a number of extra elements (as many as the max number of elements you ever expect to have in a row) that are given zero height. Space is still divided, but superfluous rows collapse to nothing:
http://codepen.io/dalgard/pen/Dbnus
body {
padding: 5%;
}
div {
overflow: hidden;
background-color: yellow;
}
ul {
display: flex;
flex-wrap: wrap;
margin: 0 -4px -4px 0;
list-style: none;
padding: 0;
}
li {
flex: 1 0 200px;
height: 200px;
border-right: 4px solid black;
border-bottom: 4px solid black;
background-color: deeppink;
}
li:empty {
height: 0;
border: none;
}
*,
:before,
:after {
box-sizing: border-box;
}
<div>
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
<li>g</li>
<li>h</li>
<li>i</li>
<li>j</li>
<li>k</li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
In the future, this may become achievable through using multiple ::after(n).
Without any extra markup, just adding ::after worked for me specifying the width of the column.
.grid {
display:flex;
justify-content:space-between;
flex-wrap:wrap;
}
.grid::after{
content: '';
width: 10em // Same width of .grid__element
}
.grid__element{
width:10em;
}
With the HTML like this:
<div class=grid">
<div class="grid__element"></div>
<div class="grid__element"></div>
<div class="grid__element"></div>
</div>
I know there are many answers here but.. The simplest way to do this is with a grid instead of flex and grid template columns with repeat and auto fills, where you have to set the number of pixels that you have given to each element, 100px from your snippet code.
.exposegrid {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
justify-content: space-between;
}
.exposetab {
width: 100px;
height: 66px;
background-color: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(0, 0, 0, 0.4);
border-radius: 5px;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
margin-bottom: 10px;
}
<div class="exposegrid">
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
</div>
You can't. Flexbox is not a grid system. It does not have the language constructs to do what you're asking for, at least not if you're using justify-content: space-between. The closest you can get with Flexbox is to use the column orientation, which requires setting an explicit height:
http://cssdeck.com/labs/pvsn6t4z (note: prefixes not included)
ul {
display: flex;
flex-flow: column wrap;
align-content: space-between;
height: 4em;
}
However, it would be simpler to just use columns, which has better support and doesn't require setting a specific height:
http://cssdeck.com/labs/dwq3x6vr (note: prefixes not included)
ul {
columns: 15em;
}
A possible solution is to use justify-content: flex-start; on the .grid container, size restrictions on its children, and margins on the appropriate child elements -- depending on the desired number of columns.
For a 3-column grid, the basic CSS would look like this:
.grid {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
}
.grid > * {
flex: 0 0 32%;
margin: 1% 0;
}
.grid > :nth-child(3n-1) {
margin-left: 2%;
margin-right: 2%;
}
It's another imperfect solution, but it works.
http://codepen.io/tuxsudo/pen/VYERQJ
Also you can do this:
.exposegrid:last-child {
margin-right: auto;
}
This problem was solved for me using CSS grid,
This solution is applicable only if you're having fix number of columns i.e. no. of elements to display in a single row
-> using grid but not specifying number of rows, as number of elements increase it wraps into columns and add rows dynamically, I have specified three columns in this example
-> you don't have to give any position to your child/cells, as it will make it fix, which we don't want.
.grid-class{
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 80px;
}
If you want a grid with some space between the items and the items starting without any initial space then this simple solution works:
.grid {
display: flex;
flex-flow: row wrap;
margin: 0 -5px; // remove the inital 5px space
width: auto;
}
.grid__item {
width: 25%;
padding: 0 5px; // should be same as the negative margin above.
}
If you want the initial 5px space then just remove the negative margin :) Simple.
https://jsfiddle.net/b97ewrno/2/
The accepted answer, whilst good, it causes there to be no space between the elements on the second row..
Yes.! We can but with some media queries & Maximum no of columns are predefined.
Here am using 4 columns. Check my code:
.container {
display: flex;
display: -webkit-flex;
display: -moz-flex;
flex-flow: row wrap;
-webkit-flex-flow: row wrap;
-moz-flex-flow: row wrap;
}
.container .item {
display: flex;
display: -webkit-flex;
display: -moz-flex;
justify-content: center;
-webkit-justify-content: center;
-moz-justify-content: center;
flex-basis: 25%; //max no of columns in %, 25% = 4 Columns
}
.container .item .item-child {
width: 130px;
height: 180px;
background: red;
margin: 10px;
}
#media (max-width: 360px) {
.container .item {
flex-basis: 100%;
}
}
#media (min-width:360px) and (max-width: 520px) {
.container .item {
flex-basis: 50%;
}
}
#media (min-width:520px) and (max-width: 680px) {
.container .item {
flex-basis: 33.33%;
}
}
<div class="container">
<div class="item">
<div class="item-child">1</div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
</div>
NOTE
1) No need to create child div. It may be any other tag like 'img' r whatever you want..
2) If you want more columns adjust the media queries and maximum no.of columns.
If you want to align the last item to the grid use the following code:
Grid container
.card-grid {
box-sizing: border-box;
max-height: 100%;
display: flex;
flex-direction: row;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
justify-content: space-between;
align-items: stretch;
align-content: stretch;
-webkit-box-align: stretch;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
}
.card-grid:after {
content: "";
flex: 1 1 100%;
max-width: 32%;
}
Item in the grid
.card {
flex: 1 1 100%;
box-sizing: border-box;
-webkit-box-flex: 1;
max-width: 32%;
display: block;
position: relative;
}
The trick is to set the max-width of the item equal to the max-width of the .card-grid:after.
Live demo on Codepen
It is possible to use "flex-start" and to add the margins manually. It requires some math-hacking but is definitely easy to do and make it easy to use with a CSS preprocessor like LESS.
See for example this LESS mixin:
.flexboxGridMixin(#columnNumber,#spacingPercent) {
#contentPercent: 100% - #spacingPercent;
#sideMargin: #spacingPercent/(#columnNumber*2);
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
> * {
box-sizing: border-box;
width: #contentPercent/#columnNumber;
margin-left: #sideMargin;
margin-right: #sideMargin;
}
}
And then it can easily be used to display a responsive grid layout:
ul {
list-style: none;
padding: 0;
#spacing: 10%;
#media only screen and (max-width: 499px) { .flexboxGridMixin(1,#spacing); }
#media only screen and (min-width: 500px) { .flexboxGridMixin(2,#spacing); }
#media only screen and (min-width: 700px) { .flexboxGridMixin(3,#spacing); }
#media only screen and (min-width: 900px) { .flexboxGridMixin(4,#spacing); }
#media only screen and (min-width: 1100px) { .flexboxGridMixin(5,#spacing); }
}
li {
background: pink;
height: 100px;
margin-top: 20px;
}
Here is an example of
http://codepen.io/anon/pen/YyLqVB?editors=110
This is a combination of a lot of the answers but it does exactly what I was needing -- which is, aligning the last child in a flex container to the left while maintaining the space-between behavior (in this case it's a three-column layout).
Here's the markup:
.flex-container {
display: flex;
justify-content: space-between;
flex-direction: row;
}
.flex-container:after {
content: "";
flex-basis: 30%;
}
If you wish to align item in grid view with equal distance for even the last element. Make sure you card width is 100%
Use the following css. This works pretty well
.container {
/* ... snip ... */
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
justify-content: space-between;
grid-gap: 20px;
}
This version is best way for blocks with fixed width:
http://codepen.io/7iomka/pen/oxxeNE
In other cases - version of dalgard
http://codepen.io/dalgard/pen/Dbnus
body {
padding: 5%;
}
div {
overflow: hidden;
background-color: yellow;
}
ul {
display: flex;
flex-wrap: wrap;
justify-content:center;
margin: 0 -4px -4px 0;
list-style: none;
padding: 0;
}
li {
flex: 1 0 200px;
height: 200px;
max-width:200px;
min-width:200px;
border-right: 4px solid black;
border-bottom: 4px solid black;
background-color: deeppink;
}
li:empty {
height: 0;
border: none;
}
*,
:before,
:after {
box-sizing: border-box;
}
<div>
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
<li>g</li>
<li>h</li>
<li>i</li>
<li>j</li>
<li>k</li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
Just add few fake items with same properties except for height set to 0px to the end.
Even though gap is coming to Flexbox I will add a solution that works.
It uses the sibling combinator to check 2 conditions.
The first condition it checks is if an element is the second to last div:nth-last-child(2)
For 4 column layouts we need to check for postions 2 & 3
Check if it is in the second row of 4 div:nth-of-type(4n+2) or third in a row div:nth-of-type(4n+3)
For 3 column layouts we only need to check position 2
div:nth-of-type(3n+2)
We can then combine like below for 4 column layouts
div:nth-last-child(2) + div:nth-of-type(4n+2)
div:nth-last-child(2) + div:nth-of-type(4n+3)
We also need to take care of one edge case, Any number that is 3n+2 & multiple of 4 will get the 35% margin-right div:nth-last-child(2) + div:nth-of-type(4n+4)
3 column layouts will be
div:nth-last-child(2) + div:nth-of-type(3n+2)
Then we need to add a margin to the above selectors. The margin-right will need to be calculated and will depend on the flex-basis.
I have added a sample with 3 and 4 columns and a media query. I have also added a small JavaScript button that adds a new div so you can check it works.
It is a little bit of CSS but it works.
I also wrote about this on my site if you want a little more explanation.
https://designkojo.com/css-programming-using-css-pseudo-classes-and-combinators
var number = 11;
$("#add").on("click", function() {
number = number + 1;
$("#main").append("<div>" + number + "</div>");
});
body {
margin: 0;
}
main{
display: flex;
flex-wrap: wrap;
align-items: flex-start;
align-content: flex-start; /* vertical */
justify-content: space-between;
min-width: 300px;
max-width: 1200px;
margin: 20px auto;
background-color: lightgrey;
height: 100vh;
}
div {
flex-basis: 30%;
background-color: #5F3BB3;
min-height: 20px;
height: 50px;
margin-bottom: 20px;
display: flex;
justify-content: center;
align-items: center;
color: #9af3ff;
font-size: 3em;
}
div:nth-last-child(2) + div:nth-of-type(3n+2) {
background-color: #f1b73e;
margin-right: 35%;
}
#media screen and (min-width: 720px) {
div {
flex-basis: 22%;
}
div:nth-last-child(2) {
background-color: greenyellow;
}
div:nth-of-type(4n+2) {
background-color: deeppink;
}
/* Using Plus combinator is for direct sibling */
div:nth-last-child(2) + div:nth-of-type(4n+2) {
background-color: #f1b73e;
margin-right: 52%;
}
div:nth-last-child(2) + div:nth-of-type(4n+3) {
background-color: #f1b73e;
margin-right: 26%;
}
/* Also need to set the last to 0% to override when it become (3n+2)
* Any number that is 3n+2 & multiple of 4 will get the 35% margin-right
* div:nth-last-child(2) + div:nth-of-type(3n+2)
*/
div:nth-last-child(2) + div:nth-of-type(4n+4) {
background-color: #f1b73e;
margin-right: 0;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>My New Project</title>
</head>
<body>
<header>
</header>
<button id="add">Add</button>
<main id="main">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="action.js"></script>
</body>
</html>
I liked the simplicity in the answer from #Dan Andreasson & #Robin Métral.. however it didn't work entirely for me.
So instead of:
.grid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.grid::after {
content: "";
flex: auto;
}
I used:
.grid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.grid::after {
content: "";
width: calc(100%/3 - 20px); /* whatever width grid items are */
}
so far, it seems to work as intended.
There is a way without flexbox, although you'd need to meet the following conditions. 1) The container has padding. 2) Items are the same size and you know exactly how many you want per line.
ul {
padding: 0 3% 0 5%;
}
li {
display: inline-block;
padding: 0 2% 2% 0;
width: 28.66%;
}
The smaller padding on the right side of the container allows for the extra padding to the right of each list item. Assuming other items in the same parent as the list object are padded with 0 5%, it will be flush with them. You can also adjust the percentages to however much margin you'd like or use calculate px values.
Of course, you can do the same without the padding on the container by using nth-child (IE 9+) to remove margin on every third box.
Using flexbox and a few media queries, I made this little work-around: http://codepen.io/una/pen/yNEGjv (its a bit hacky but works):
.container {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
max-width: 1200px;
margin: 0 auto;
}
.item {
background-color: gray;
height: 300px;
flex: 0 30%;
margin: 10px;
#media (max-width: 700px) {
flex: 0 45%;
}
#media (max-width: 420px) {
flex: 0 100%;
}
&:nth-child(3n-1) {
margin-left: 10px;
margin-right: 10px;
}
}
This is pretty hacky, but it works for me. I was trying to achieve consistent spacing/margins.
.grid {
width: 1024px;
display: flex;
flex-flow: row wrap;
padding: 32px;
background-color: #ddd;
&:after {
content: "";
flex: auto;
margin-left:-1%;
}
.item {
flex: 1 0 24.25%;
max-width: 24.25%;
margin-bottom: 10px;
text-align: center;
background-color: #bbb;
&:nth-child(4n+2),
&:nth-child(4n+3),
&:nth-child(4n+4) {
margin-left: 1%;
}
&:nth-child(4n+1):nth-last-child(-n+4),
&:nth-child(4n+1):nth-last-child(-n+4) ~ .item {
margin-bottom: 0;
}
}
}
http://codepen.io/rustydev/pen/f7c8920e0beb0ba9a904da7ebd9970ae/
Seems like no one proposed the flex-grow solution on last item.
The idea is to have your last flex item to take all the place it can using flex-grow: 1.
.grid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.grid > *:last-child {
flex-grow: 1;
}
Note: This solution is not perfect, especially if you have centered elements inside your flex items as it will center on the possibly huge last flex item.
Oh boy, I think I found a good solution with minimal CSS and no JS. Check it out:
img {width:100%;}
li {
display: inline-block;
width:8em;
list-style:none;
}
ul {text-align: justify;}
<ul>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
The key here is to remember that what we are trying to achieve is exactly what text-align: justify does!
The empty elements in the HTML are there to make the last row display perfectly without changing the appearance, but might not be needed given what you are trying to achieve. For perfect balance in every situation, you need at least x-4 empty elements, x being the number of elements to display, or n-2, n being the number of column you want to display.
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 and 9th item and so on. If the left margin is 10px then each row will have 30px margin distributed among 4 items. The percentage width for item is 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 3em;
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>
If you know the width of spaces between elements in the row and the amount of elements in a row, this would work:
Example: 3 elements in a row, 10px gap between elements
div:last-child:nth-child(3n+2) {
flex-grow: 1
margin-left: 10px
}
I modified the example presented by Dan Andreasson by using a right border on elements to create a faux gutter. You can then use nth-child to remove the border on the last-child of the column grid count you need. here is a demo https://codepen.io/JacobLett/pen/mdVoroM
/* demo only */
body {
margin:0;
padding:0;
max-width:1024px;
margin:0 auto;
}
.block-list {
background: #ccc;
border:1px solid #ccc;
}
.block-list .block-list__item {
background: #eee;
}
/* demo only */
.block-list .block-list__item {
min-height: 100px;
margin-bottom: 1rem;
}
#media only screen and (min-width: 900px) {
.block-list {
display: -webkit-box;
display: flex;
flex-wrap: wrap;
-webkit-box-pack: justify;
justify-content: space-between;
background-color: #ffffff;
margin: 1em auto;
}
.block-list:after {
content: "";
-webkit-box-flex: 1;
flex: auto;
}
.block-list__item {
height: 10em;
width: 25%;
box-sizing: border-box;
border-right: 10px solid white;
}
.block-list-2 .block-list__item {
width: 50%;
}
.block-list-2 .block-list__item:nth-child(2n) {
border: none;
}
.block-list-3 .block-list__item {
width: 33.3%;
}
.block-list-3 .block-list__item:nth-child(3n) {
border: none;
}
.block-list-4 .block-list__item {
width: 25%;
}
.block-list-4 .block-list__item:nth-child(4n) {
border: none;
}
.block-list-5 .block-list__item {
width: 20%;
}
.block-list-5 .block-list__item:nth-child(5n) {
border: none;
}
.block-list-6 .block-list__item {
width: 16.66%;
}
.block-list-6 .block-list__item:nth-child(6n) {
border: none;
}
}
<h2>2 column</h2>
<div class="block-list block-list-2">
<div class="block-list__item">1
</div>
<div class="block-list__item">2
</div>
<div class="block-list__item">3
</div>
<div class="block-list__item">4
</div>
<div class="block-list__item">5
</div>
<div class="block-list__item">6
</div>
</div>
<h2>3 column</h2>
<div class="block-list block-list-3">
<div class="block-list__item">1
</div>
<div class="block-list__item">2
</div>
<div class="block-list__item">3
</div>
<div class="block-list__item">4
</div>
<div class="block-list__item">5
</div>
<div class="block-list__item">6
</div>
</div>
<h2>4 column</h2>
<div class="block-list block-list-4">
<div class="block-list__item">1
</div>
<div class="block-list__item">2
</div>
<div class="block-list__item">3
</div>
<div class="block-list__item">4
</div>
<div class="block-list__item">5
</div>
<div class="block-list__item">6
</div>
</div>
<h2>5 column</h2>
<div class="block-list block-list-5">
<div class="block-list__item">1
</div>
<div class="block-list__item">2
</div>
<div class="block-list__item">3
</div>
<div class="block-list__item">4
</div>
<div class="block-list__item">5
</div>
<div class="block-list__item">6
</div>
</div>
<h2>6 column</h2>
<div class="block-list block-list-6">
<div class="block-list__item">1
</div>
<div class="block-list__item">2
</div>
<div class="block-list__item">3
</div>
<div class="block-list__item">4
</div>
<div class="block-list__item">5
</div>
<div class="block-list__item">6
</div>
</div>
If the individual child items have an explicit width (eg. 32%), you can solve this by adding an :after element to the parent and giving this the same explicit width.
There are solutions here where people suggest writing exact layout css-classes, faking the last item with pseudo-element, using non-flexbox approaches etc.
One big problem is the gaps between neighbors (case - aligned buttons wrapping to multiple lines). In such a case, you don't want the items to touch each other, there is a need for gaps. I just want to add an adoptive solution that respects gaps and works with any number of items. It is based on the idea of fake last element too though, but is more universal. See snippet comments for details.
html {
font-size: 1px;
}
.container {
font-size: 16rem;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.item {
background-color: orange;
border-radius: 10rem;
box-sizing: border-box;
color: white;
margin-bottom: 10rem;
padding: 15rem 10rem;
text-align: center;
}
<!--
Our setup from design (example) used later in calculations:
container-width: 100%; (can be any)
max-per-row = 4;
total = 6;
desired-hor-gap = 10rem; (equal to vert. gap)
If you go dynamic (drawing html according to the coming data either in a backend template or in a frontend template), you have to calculate and then set exact properties inline.
<i> (or any real html element) is needed to set inline styles to arrange the last row properly.
"2" in <i> calc function - is 6 % 4 since calc doesn't allow for "%" operator. But in real life you will calculate these numbers in JS or some backend template anyway.
Formulas written in elements' calc functions. Seem to be self-descriptive, but the idea is to set for the last fake item the remainder width + hypothetical gaps.
-->
<div class="container">
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<i style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4 * (4 - 2) + ( 4 - 2 - 1) * 10rem);"></i>
</div>
I found an efficient solution that the justify-content can be also center / space-evenly / etc... (if you know the number of items in a single row):
HTML:
<section class="container">
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<p aria-hidden="true"></p>
<p aria-hidden="true"></p>
<p aria-hidden="true"></p>
</section>
The number of <p> tags (it can be any other tag) is the number of items in each row minus 1. With different screen sizes you can manipulate it with media queries.
CSS:
.container {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
}
.flex-item {
width: 300px;
height: 300px;
background: #21BA45;
}
.container > p {
width: 300px;
height: 300px;
}

How can I align flex items to the start of the main axis? [duplicate]

I have a simple flex-box layout with a container like:
.grid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
Now I want the items in the last row to be aligned with the other. justify-content: space-between; should be used because the width and height of the grid can be adjusted.
Currently it looks like
Here, I want the item in the bottom right to be in the "middle column". What is the simplest way to accomplish that? Here is a small jsfiddle that shows this behaviour.
.exposegrid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.exposetab {
width: 100px;
height: 66px;
background-color: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(0, 0, 0, 0.4);
border-radius: 5px;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
margin-bottom: 10px;
}
<div class="exposegrid">
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
</div>
Add a ::after which autofills the space. No need to pollute your HTML. Here is a codepen showing it: http://codepen.io/DanAndreasson/pen/ZQXLXj
.grid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.grid::after {
content: "";
flex: auto;
}
As other posters have mentioned - there's no clean way to left-align the last row with flexbox (at least as per the current spec)
However, for what it's worth: With the CSS Grid Layout Module this is surprisingly easy to produce:
Basically the relevant code boils down to this:
ul {
display: grid; /* 1 */
grid-template-columns: repeat(auto-fill, 100px); /* 2 */
grid-gap: 1rem; /* 3 */
justify-content: space-between; /* 4 */
}
1) Make the container element a grid container
2) Set the grid with auto columns of width 100px. (Note the use of auto-fill (as apposed to auto-fit - which (for a 1-row layout) collapses empty tracks to 0 - causing the items to expand to take up the remaining space. This would result in a justified 'space-between' layout when grid has only one row which in our case is not what we want. (check out this demo to see the difference between them)).
3) Set gaps/gutters for the grid rows and columns - here, since want a 'space-between' layout - the gap will actually be a minimum gap because it will grow as necessary.
4) Similar to flexbox.
ul {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
grid-gap: 1rem;
justify-content: space-between;
/* boring properties */
list-style: none;
background: wheat;
padding: 2rem;
width: 80vw;
margin: 0 auto;
}
li {
height: 50px;
border: 1px solid green;
}
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
Codepen Demo (Resize to see the effect)
One technique would be inserting a number of extra elements (as many as the max number of elements you ever expect to have in a row) that are given zero height. Space is still divided, but superfluous rows collapse to nothing:
http://codepen.io/dalgard/pen/Dbnus
body {
padding: 5%;
}
div {
overflow: hidden;
background-color: yellow;
}
ul {
display: flex;
flex-wrap: wrap;
margin: 0 -4px -4px 0;
list-style: none;
padding: 0;
}
li {
flex: 1 0 200px;
height: 200px;
border-right: 4px solid black;
border-bottom: 4px solid black;
background-color: deeppink;
}
li:empty {
height: 0;
border: none;
}
*,
:before,
:after {
box-sizing: border-box;
}
<div>
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
<li>g</li>
<li>h</li>
<li>i</li>
<li>j</li>
<li>k</li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
In the future, this may become achievable through using multiple ::after(n).
Without any extra markup, just adding ::after worked for me specifying the width of the column.
.grid {
display:flex;
justify-content:space-between;
flex-wrap:wrap;
}
.grid::after{
content: '';
width: 10em // Same width of .grid__element
}
.grid__element{
width:10em;
}
With the HTML like this:
<div class=grid">
<div class="grid__element"></div>
<div class="grid__element"></div>
<div class="grid__element"></div>
</div>
I know there are many answers here but.. The simplest way to do this is with a grid instead of flex and grid template columns with repeat and auto fills, where you have to set the number of pixels that you have given to each element, 100px from your snippet code.
.exposegrid {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
justify-content: space-between;
}
.exposetab {
width: 100px;
height: 66px;
background-color: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(0, 0, 0, 0.4);
border-radius: 5px;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
margin-bottom: 10px;
}
<div class="exposegrid">
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
<div class="exposetab"></div>
</div>
You can't. Flexbox is not a grid system. It does not have the language constructs to do what you're asking for, at least not if you're using justify-content: space-between. The closest you can get with Flexbox is to use the column orientation, which requires setting an explicit height:
http://cssdeck.com/labs/pvsn6t4z (note: prefixes not included)
ul {
display: flex;
flex-flow: column wrap;
align-content: space-between;
height: 4em;
}
However, it would be simpler to just use columns, which has better support and doesn't require setting a specific height:
http://cssdeck.com/labs/dwq3x6vr (note: prefixes not included)
ul {
columns: 15em;
}
A possible solution is to use justify-content: flex-start; on the .grid container, size restrictions on its children, and margins on the appropriate child elements -- depending on the desired number of columns.
For a 3-column grid, the basic CSS would look like this:
.grid {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
}
.grid > * {
flex: 0 0 32%;
margin: 1% 0;
}
.grid > :nth-child(3n-1) {
margin-left: 2%;
margin-right: 2%;
}
It's another imperfect solution, but it works.
http://codepen.io/tuxsudo/pen/VYERQJ
Also you can do this:
.exposegrid:last-child {
margin-right: auto;
}
This problem was solved for me using CSS grid,
This solution is applicable only if you're having fix number of columns i.e. no. of elements to display in a single row
-> using grid but not specifying number of rows, as number of elements increase it wraps into columns and add rows dynamically, I have specified three columns in this example
-> you don't have to give any position to your child/cells, as it will make it fix, which we don't want.
.grid-class{
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 80px;
}
If you want a grid with some space between the items and the items starting without any initial space then this simple solution works:
.grid {
display: flex;
flex-flow: row wrap;
margin: 0 -5px; // remove the inital 5px space
width: auto;
}
.grid__item {
width: 25%;
padding: 0 5px; // should be same as the negative margin above.
}
If you want the initial 5px space then just remove the negative margin :) Simple.
https://jsfiddle.net/b97ewrno/2/
The accepted answer, whilst good, it causes there to be no space between the elements on the second row..
Yes.! We can but with some media queries & Maximum no of columns are predefined.
Here am using 4 columns. Check my code:
.container {
display: flex;
display: -webkit-flex;
display: -moz-flex;
flex-flow: row wrap;
-webkit-flex-flow: row wrap;
-moz-flex-flow: row wrap;
}
.container .item {
display: flex;
display: -webkit-flex;
display: -moz-flex;
justify-content: center;
-webkit-justify-content: center;
-moz-justify-content: center;
flex-basis: 25%; //max no of columns in %, 25% = 4 Columns
}
.container .item .item-child {
width: 130px;
height: 180px;
background: red;
margin: 10px;
}
#media (max-width: 360px) {
.container .item {
flex-basis: 100%;
}
}
#media (min-width:360px) and (max-width: 520px) {
.container .item {
flex-basis: 50%;
}
}
#media (min-width:520px) and (max-width: 680px) {
.container .item {
flex-basis: 33.33%;
}
}
<div class="container">
<div class="item">
<div class="item-child">1</div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
<div class="item">
<div class="item-child"></div>
</div>
</div>
NOTE
1) No need to create child div. It may be any other tag like 'img' r whatever you want..
2) If you want more columns adjust the media queries and maximum no.of columns.
If you want to align the last item to the grid use the following code:
Grid container
.card-grid {
box-sizing: border-box;
max-height: 100%;
display: flex;
flex-direction: row;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
justify-content: space-between;
align-items: stretch;
align-content: stretch;
-webkit-box-align: stretch;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
}
.card-grid:after {
content: "";
flex: 1 1 100%;
max-width: 32%;
}
Item in the grid
.card {
flex: 1 1 100%;
box-sizing: border-box;
-webkit-box-flex: 1;
max-width: 32%;
display: block;
position: relative;
}
The trick is to set the max-width of the item equal to the max-width of the .card-grid:after.
Live demo on Codepen
It is possible to use "flex-start" and to add the margins manually. It requires some math-hacking but is definitely easy to do and make it easy to use with a CSS preprocessor like LESS.
See for example this LESS mixin:
.flexboxGridMixin(#columnNumber,#spacingPercent) {
#contentPercent: 100% - #spacingPercent;
#sideMargin: #spacingPercent/(#columnNumber*2);
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
> * {
box-sizing: border-box;
width: #contentPercent/#columnNumber;
margin-left: #sideMargin;
margin-right: #sideMargin;
}
}
And then it can easily be used to display a responsive grid layout:
ul {
list-style: none;
padding: 0;
#spacing: 10%;
#media only screen and (max-width: 499px) { .flexboxGridMixin(1,#spacing); }
#media only screen and (min-width: 500px) { .flexboxGridMixin(2,#spacing); }
#media only screen and (min-width: 700px) { .flexboxGridMixin(3,#spacing); }
#media only screen and (min-width: 900px) { .flexboxGridMixin(4,#spacing); }
#media only screen and (min-width: 1100px) { .flexboxGridMixin(5,#spacing); }
}
li {
background: pink;
height: 100px;
margin-top: 20px;
}
Here is an example of
http://codepen.io/anon/pen/YyLqVB?editors=110
This is a combination of a lot of the answers but it does exactly what I was needing -- which is, aligning the last child in a flex container to the left while maintaining the space-between behavior (in this case it's a three-column layout).
Here's the markup:
.flex-container {
display: flex;
justify-content: space-between;
flex-direction: row;
}
.flex-container:after {
content: "";
flex-basis: 30%;
}
If you wish to align item in grid view with equal distance for even the last element. Make sure you card width is 100%
Use the following css. This works pretty well
.container {
/* ... snip ... */
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
justify-content: space-between;
grid-gap: 20px;
}
This version is best way for blocks with fixed width:
http://codepen.io/7iomka/pen/oxxeNE
In other cases - version of dalgard
http://codepen.io/dalgard/pen/Dbnus
body {
padding: 5%;
}
div {
overflow: hidden;
background-color: yellow;
}
ul {
display: flex;
flex-wrap: wrap;
justify-content:center;
margin: 0 -4px -4px 0;
list-style: none;
padding: 0;
}
li {
flex: 1 0 200px;
height: 200px;
max-width:200px;
min-width:200px;
border-right: 4px solid black;
border-bottom: 4px solid black;
background-color: deeppink;
}
li:empty {
height: 0;
border: none;
}
*,
:before,
:after {
box-sizing: border-box;
}
<div>
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
<li>g</li>
<li>h</li>
<li>i</li>
<li>j</li>
<li>k</li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
Just add few fake items with same properties except for height set to 0px to the end.
Even though gap is coming to Flexbox I will add a solution that works.
It uses the sibling combinator to check 2 conditions.
The first condition it checks is if an element is the second to last div:nth-last-child(2)
For 4 column layouts we need to check for postions 2 & 3
Check if it is in the second row of 4 div:nth-of-type(4n+2) or third in a row div:nth-of-type(4n+3)
For 3 column layouts we only need to check position 2
div:nth-of-type(3n+2)
We can then combine like below for 4 column layouts
div:nth-last-child(2) + div:nth-of-type(4n+2)
div:nth-last-child(2) + div:nth-of-type(4n+3)
We also need to take care of one edge case, Any number that is 3n+2 & multiple of 4 will get the 35% margin-right div:nth-last-child(2) + div:nth-of-type(4n+4)
3 column layouts will be
div:nth-last-child(2) + div:nth-of-type(3n+2)
Then we need to add a margin to the above selectors. The margin-right will need to be calculated and will depend on the flex-basis.
I have added a sample with 3 and 4 columns and a media query. I have also added a small JavaScript button that adds a new div so you can check it works.
It is a little bit of CSS but it works.
I also wrote about this on my site if you want a little more explanation.
https://designkojo.com/css-programming-using-css-pseudo-classes-and-combinators
var number = 11;
$("#add").on("click", function() {
number = number + 1;
$("#main").append("<div>" + number + "</div>");
});
body {
margin: 0;
}
main{
display: flex;
flex-wrap: wrap;
align-items: flex-start;
align-content: flex-start; /* vertical */
justify-content: space-between;
min-width: 300px;
max-width: 1200px;
margin: 20px auto;
background-color: lightgrey;
height: 100vh;
}
div {
flex-basis: 30%;
background-color: #5F3BB3;
min-height: 20px;
height: 50px;
margin-bottom: 20px;
display: flex;
justify-content: center;
align-items: center;
color: #9af3ff;
font-size: 3em;
}
div:nth-last-child(2) + div:nth-of-type(3n+2) {
background-color: #f1b73e;
margin-right: 35%;
}
#media screen and (min-width: 720px) {
div {
flex-basis: 22%;
}
div:nth-last-child(2) {
background-color: greenyellow;
}
div:nth-of-type(4n+2) {
background-color: deeppink;
}
/* Using Plus combinator is for direct sibling */
div:nth-last-child(2) + div:nth-of-type(4n+2) {
background-color: #f1b73e;
margin-right: 52%;
}
div:nth-last-child(2) + div:nth-of-type(4n+3) {
background-color: #f1b73e;
margin-right: 26%;
}
/* Also need to set the last to 0% to override when it become (3n+2)
* Any number that is 3n+2 & multiple of 4 will get the 35% margin-right
* div:nth-last-child(2) + div:nth-of-type(3n+2)
*/
div:nth-last-child(2) + div:nth-of-type(4n+4) {
background-color: #f1b73e;
margin-right: 0;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>My New Project</title>
</head>
<body>
<header>
</header>
<button id="add">Add</button>
<main id="main">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="action.js"></script>
</body>
</html>
I liked the simplicity in the answer from #Dan Andreasson & #Robin Métral.. however it didn't work entirely for me.
So instead of:
.grid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.grid::after {
content: "";
flex: auto;
}
I used:
.grid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.grid::after {
content: "";
width: calc(100%/3 - 20px); /* whatever width grid items are */
}
so far, it seems to work as intended.
There is a way without flexbox, although you'd need to meet the following conditions. 1) The container has padding. 2) Items are the same size and you know exactly how many you want per line.
ul {
padding: 0 3% 0 5%;
}
li {
display: inline-block;
padding: 0 2% 2% 0;
width: 28.66%;
}
The smaller padding on the right side of the container allows for the extra padding to the right of each list item. Assuming other items in the same parent as the list object are padded with 0 5%, it will be flush with them. You can also adjust the percentages to however much margin you'd like or use calculate px values.
Of course, you can do the same without the padding on the container by using nth-child (IE 9+) to remove margin on every third box.
Using flexbox and a few media queries, I made this little work-around: http://codepen.io/una/pen/yNEGjv (its a bit hacky but works):
.container {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
max-width: 1200px;
margin: 0 auto;
}
.item {
background-color: gray;
height: 300px;
flex: 0 30%;
margin: 10px;
#media (max-width: 700px) {
flex: 0 45%;
}
#media (max-width: 420px) {
flex: 0 100%;
}
&:nth-child(3n-1) {
margin-left: 10px;
margin-right: 10px;
}
}
This is pretty hacky, but it works for me. I was trying to achieve consistent spacing/margins.
.grid {
width: 1024px;
display: flex;
flex-flow: row wrap;
padding: 32px;
background-color: #ddd;
&:after {
content: "";
flex: auto;
margin-left:-1%;
}
.item {
flex: 1 0 24.25%;
max-width: 24.25%;
margin-bottom: 10px;
text-align: center;
background-color: #bbb;
&:nth-child(4n+2),
&:nth-child(4n+3),
&:nth-child(4n+4) {
margin-left: 1%;
}
&:nth-child(4n+1):nth-last-child(-n+4),
&:nth-child(4n+1):nth-last-child(-n+4) ~ .item {
margin-bottom: 0;
}
}
}
http://codepen.io/rustydev/pen/f7c8920e0beb0ba9a904da7ebd9970ae/
Seems like no one proposed the flex-grow solution on last item.
The idea is to have your last flex item to take all the place it can using flex-grow: 1.
.grid {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.grid > *:last-child {
flex-grow: 1;
}
Note: This solution is not perfect, especially if you have centered elements inside your flex items as it will center on the possibly huge last flex item.
Oh boy, I think I found a good solution with minimal CSS and no JS. Check it out:
img {width:100%;}
li {
display: inline-block;
width:8em;
list-style:none;
}
ul {text-align: justify;}
<ul>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li>
<img src="http://www.planwallpaper.com/static/images/kitty-cat.jpg" />
</li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
The key here is to remember that what we are trying to achieve is exactly what text-align: justify does!
The empty elements in the HTML are there to make the last row display perfectly without changing the appearance, but might not be needed given what you are trying to achieve. For perfect balance in every situation, you need at least x-4 empty elements, x being the number of elements to display, or n-2, n being the number of column you want to display.
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 and 9th item and so on. If the left margin is 10px then each row will have 30px margin distributed among 4 items. The percentage width for item is 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 3em;
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>
If you know the width of spaces between elements in the row and the amount of elements in a row, this would work:
Example: 3 elements in a row, 10px gap between elements
div:last-child:nth-child(3n+2) {
flex-grow: 1
margin-left: 10px
}
I modified the example presented by Dan Andreasson by using a right border on elements to create a faux gutter. You can then use nth-child to remove the border on the last-child of the column grid count you need. here is a demo https://codepen.io/JacobLett/pen/mdVoroM
/* demo only */
body {
margin:0;
padding:0;
max-width:1024px;
margin:0 auto;
}
.block-list {
background: #ccc;
border:1px solid #ccc;
}
.block-list .block-list__item {
background: #eee;
}
/* demo only */
.block-list .block-list__item {
min-height: 100px;
margin-bottom: 1rem;
}
#media only screen and (min-width: 900px) {
.block-list {
display: -webkit-box;
display: flex;
flex-wrap: wrap;
-webkit-box-pack: justify;
justify-content: space-between;
background-color: #ffffff;
margin: 1em auto;
}
.block-list:after {
content: "";
-webkit-box-flex: 1;
flex: auto;
}
.block-list__item {
height: 10em;
width: 25%;
box-sizing: border-box;
border-right: 10px solid white;
}
.block-list-2 .block-list__item {
width: 50%;
}
.block-list-2 .block-list__item:nth-child(2n) {
border: none;
}
.block-list-3 .block-list__item {
width: 33.3%;
}
.block-list-3 .block-list__item:nth-child(3n) {
border: none;
}
.block-list-4 .block-list__item {
width: 25%;
}
.block-list-4 .block-list__item:nth-child(4n) {
border: none;
}
.block-list-5 .block-list__item {
width: 20%;
}
.block-list-5 .block-list__item:nth-child(5n) {
border: none;
}
.block-list-6 .block-list__item {
width: 16.66%;
}
.block-list-6 .block-list__item:nth-child(6n) {
border: none;
}
}
<h2>2 column</h2>
<div class="block-list block-list-2">
<div class="block-list__item">1
</div>
<div class="block-list__item">2
</div>
<div class="block-list__item">3
</div>
<div class="block-list__item">4
</div>
<div class="block-list__item">5
</div>
<div class="block-list__item">6
</div>
</div>
<h2>3 column</h2>
<div class="block-list block-list-3">
<div class="block-list__item">1
</div>
<div class="block-list__item">2
</div>
<div class="block-list__item">3
</div>
<div class="block-list__item">4
</div>
<div class="block-list__item">5
</div>
<div class="block-list__item">6
</div>
</div>
<h2>4 column</h2>
<div class="block-list block-list-4">
<div class="block-list__item">1
</div>
<div class="block-list__item">2
</div>
<div class="block-list__item">3
</div>
<div class="block-list__item">4
</div>
<div class="block-list__item">5
</div>
<div class="block-list__item">6
</div>
</div>
<h2>5 column</h2>
<div class="block-list block-list-5">
<div class="block-list__item">1
</div>
<div class="block-list__item">2
</div>
<div class="block-list__item">3
</div>
<div class="block-list__item">4
</div>
<div class="block-list__item">5
</div>
<div class="block-list__item">6
</div>
</div>
<h2>6 column</h2>
<div class="block-list block-list-6">
<div class="block-list__item">1
</div>
<div class="block-list__item">2
</div>
<div class="block-list__item">3
</div>
<div class="block-list__item">4
</div>
<div class="block-list__item">5
</div>
<div class="block-list__item">6
</div>
</div>
If the individual child items have an explicit width (eg. 32%), you can solve this by adding an :after element to the parent and giving this the same explicit width.
There are solutions here where people suggest writing exact layout css-classes, faking the last item with pseudo-element, using non-flexbox approaches etc.
One big problem is the gaps between neighbors (case - aligned buttons wrapping to multiple lines). In such a case, you don't want the items to touch each other, there is a need for gaps. I just want to add an adoptive solution that respects gaps and works with any number of items. It is based on the idea of fake last element too though, but is more universal. See snippet comments for details.
html {
font-size: 1px;
}
.container {
font-size: 16rem;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.item {
background-color: orange;
border-radius: 10rem;
box-sizing: border-box;
color: white;
margin-bottom: 10rem;
padding: 15rem 10rem;
text-align: center;
}
<!--
Our setup from design (example) used later in calculations:
container-width: 100%; (can be any)
max-per-row = 4;
total = 6;
desired-hor-gap = 10rem; (equal to vert. gap)
If you go dynamic (drawing html according to the coming data either in a backend template or in a frontend template), you have to calculate and then set exact properties inline.
<i> (or any real html element) is needed to set inline styles to arrange the last row properly.
"2" in <i> calc function - is 6 % 4 since calc doesn't allow for "%" operator. But in real life you will calculate these numbers in JS or some backend template anyway.
Formulas written in elements' calc functions. Seem to be self-descriptive, but the idea is to set for the last fake item the remainder width + hypothetical gaps.
-->
<div class="container">
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<div style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4);" class="item">do stuff</div>
<i style="flex: 0 1 calc((100% - (4 - 1) * 10rem) / 4 * (4 - 2) + ( 4 - 2 - 1) * 10rem);"></i>
</div>
I found an efficient solution that the justify-content can be also center / space-evenly / etc... (if you know the number of items in a single row):
HTML:
<section class="container">
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<p aria-hidden="true"></p>
<p aria-hidden="true"></p>
<p aria-hidden="true"></p>
</section>
The number of <p> tags (it can be any other tag) is the number of items in each row minus 1. With different screen sizes you can manipulate it with media queries.
CSS:
.container {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
}
.flex-item {
width: 300px;
height: 300px;
background: #21BA45;
}
.container > p {
width: 300px;
height: 300px;
}

Resources