How to not wrap an item on a new row? [duplicate] - html

This question already has answers here:
Is it possible for flex items to align tightly to the items above them?
(5 answers)
Closed 3 years ago.
As the picture describes, I want to wrap items as such.
This is my current HTML and CSS.
<div class="column-container">
<div class="col item">1 <- More text and thus taller than the other ones</div>
<div class="col item">2</div>
<div class="col item">3</div>
<div class="col item">4</div>
<div class="col item">5</div>
</div>
.column-container {
display: flex;
justify-content: center;
flex-flow: row wrap;
height: 100%;
}
.item {
height: fit-content;
min-width: 300px;
max-width: 300px;
margin: 10px;
}
Here's a fiddle as well..
https://jsfiddle.net/3Ly5zh4n/1

Flexbox is probably not the best choice for this since flexbox is used to display content next to each other either vertical or horizontal. I'd suggest using CSS Grid instead. It might be a new area for some, but it's a quite good choice for handling columns in CSS.
The following is an example of how it can be used. The method repeat(auto-fill, ...) fills the whole container with either a full fraction for each element, or the minimum width of 150px, which should be 300px in your case.
.column-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
grid-template-rows: 1fr 1fr;
grid-gap: 10px;
height: 300px;
}
.item {
display: flex;
justify-content: center;
align-items: center;
font-size: 36px;
color: white;
background-color: red;
}
.item--first {
grid-row: 1 / span 2;
}
<div class="column-container">
<div class="item item--first">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
</div>
I'd suggest reading css tricks A Complete Guide to Grid for further information. Hope this helps a bit.

.column-container {
display: flex;
flex-flow: row wrap;
height: 100%;
}
.item {
height: fit-content;
min-width: 150px;
max-width: 150px;
margin: 10px;
border: 1px solid black;
}
<div style="display: flex;justify-content: center">
<div class="column-container">
<div class="col item" style="height: 100px;">1 <- More text and thus taller than the other ones</div>
</div>
<div class="column-container">
<div class="col item">2</div>
<div class="col item">3</div>
<div class="col item">4</div>
<div class="col item">5</div>
</div>
</div>

I think this this will do what you want. Its a simpler approach but it behaves the way you explain in your requested image.
HTML:
<div>
<ul>
<!-- I have set the height of this li to 300px to demo the concept. -->
<li class="col item" style="height: 300px">
1 More text and thus taller than the other ones.
</li>
<li class="col item">2</li>
<li class="col item">3</li>
<li class="col item">4</li>
<li class="col item">5</li>
</ul>
</div>
CSS:
ul {
padding: 0;
}
ul .item {
list-style: none;
float: left;
height: 100px;
width: 300px;
margin: 10px;
border: 1px solid red;
}
This should give you a result of:
Result layout
Hope this helps...

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>

Flexbox - Laying out a photo section

My goal is to get the section looking like this:
(https://i.gyazo.com/7dd160aeadd2ed2c5f696e9cfd5158e3.png)
This is what my current code is giving me:
(https://i.gyazo.com/1fb61e98783f823f3bd003d1ffec3bf8.png)
I'm a beginner and struggle laying laying out sections. How would i get the my current code to give me what i want in the my goal image. Thanks.
My HTML for the image section
<div class="mid-section">
<div class="left-side">
<img src="340h.png" alt="">
</div>
<div class="right-side">
<img src="160hx140.png" alt="">
<img src="160hx140.png" alt="">
<img src="160hx140.png" alt="">
<img src="160hx140.png" alt="">
</div>
</div>
My CSS for the image section:
.mid-section{
width: 760px;
background-color: gray;
display: flex;
align-items: center;
justify-content: center;
margin: auto;
}
.right-side, .left-side{
justify-content: space-around;
}
.left-side img{
width:350px;
height:280px;
margin-top: 0;
}
.right-side img{
width:165px;
height:135px;
margin: 0px 20px 20px 0px;
}
.right-side{
width: 380px;
align-items: center;
justify-content: center;
}
.left-side{
width: 380px;
align-items: center;
justify-content: center;
}
CSS-grid is good for this. I simplified your HTML a bit for brevity...
HTML
<div class="mid-section">
<img src="340h.png" alt="">
<img src="160hx140.png" alt="">
<img src="160hx140.png" alt="">
<img src="160hx140.png" alt="">
<img src="160hx140.png" alt="">
</div>
CSS
.mid-section {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
grid-column-gap: 1em;
grid-row-gap: 1em;
}
.mid-section img:first-child {
grid-row-start: 1;
grid-row-end: span 2;
}
img {
border: red solid 1px;
min-height: 100px;
}
Everything you need to know about grid: https://css-tricks.com/snippets/css/complete-guide-grid/#prop-grid-column-row
Here's a basic example using CSS Grid which implements the layout you're after. I don't need to specify the grid placement for .item1 (the large image) because the placement is implicit. Also note that I use display: inline-grid, so that the width of the overall grid is as wide as the content that fills it, not 100% of the row.
.grid {
display: inline-grid;
grid-template-columns: 350px repeat(3, 1fr);
grid-template-rows: 135px 135px;
grid-gap: 10px;
}
.item2, .item4 {
grid-column: 2 / 3;
}
.item3, .item5 {
grid-column: 3 / 4;
}
<div class="grid">
<img class="item1" src="http://placekitten.com/350/280" alt="">
<img class="item2" src="http://placekitten.com/165/135" alt="">
<img class="item3" src="http://placekitten.com/165/135" alt="">
<img class="item4" src="http://placekitten.com/165/135" alt="">
<img class="item5" src="http://placekitten.com/165/135" alt="">
</div>
jsFiddle
First I'd recommend reading:
Introduction to the CSS basic box model
Next we need to break down what it is we are trying to achieve. It's typically easiest to break down a layout by rows and columns and do any spacing between elements last. Since there is an image that spans across two rows, to me, it would be easier to start with a columns. I'm starting with a border to help visually see if the layout is working as intended.
| Col 1 | Col 2 | Col 3 |
To Achieve this with flexbox:
div {
border: 2px solid blue;
}
div > div {
border: 2px solid red;
}
.d-flex {
display: flex;
}
.flex-row {
flex-direction: row;
}
<div class="d-flex flex-row">
<div> Col 1 </div>
<div> Col 2 </div>
<div> Col 3 </div>
</div>
Now we can break down columns into rows for the additional spaces required:
| Col 1 | Col 2 Row 1 | Col 3 Row 1 |
| Col 1 | Col 2 Row 2 | Col 3 Row 2 |
div {
border: 1px solid blue;
}
div > div {
border: 2px solid red;
}
div > div > div {
border: 3px solid green;
}
.d-flex {
display: flex;
}
.flex-row {
flex-direction: row;
}
.flex-column {
flex-direction: column;
}
<div class="d-flex flex-row">
<div> Col 1 </div>
<div class="d-flex flex-column">
<div> Col 2 Row 1</div>
<div> Col 2 Row 2</div>
</div>
<div class="d-flex flex-column">
<div> Col 3 Row 1</div>
<div> Col 3 Row 2</div>
</div>
</div>
Here are some assumptions Ill work against since they were not included at the time I wrote this answer; the spacing between these elements and the container elements is all the same, and we are not trying to dynamically change the images sizes to be scaled as the window grows or shrinks (we won't resize the images to fit in the space allocated, they are of a static size).
Basically My Opinion of Margins vs Padding:
Margins - When you want to separate elements from each other.
Padding - When you want the contents of your elements to be separated from the elements border.
There are many subtle differences between the two which I won't go over here. Another advantage of margins in this scenario is that we only need to apply them to the inner most containers. Since we are in a flexbox model we need to do some semi-tricky stuff to get the margins to all align correctly.
div {
border: 1px solid blue;
}
div > div {
border: 2px solid red;
}
div > div > div {
border: 3px solid green;
}
.d-flex {
display: flex;
}
.flex-row {
flex-direction: row;
}
.flex-column {
flex-direction: column;
}
.m-20 {
margin: 20px;
}
.mtr-20 {
margin: 20px 20px 0 0;
}
.mtrb-20 {
margin: 20px 20px 20px 0;
}
<div class="d-flex flex-row">
<div class="m-20"> Col 1 </div>
<div class="d-flex flex-column">
<div class="mtr-20"> Col 2 Row 1</div>
<div class="mtrb-20"> Col 2 Row 2</div>
</div>
<div class="d-flex flex-column">
<div class="mtr-20"> Col 3 Row 1</div>
<div class="mtrb-20"> Col 3 Row 2</div>
</div>
</div>
Now we can see that all the borders are lining up as needed. Now we can remove the border and insert any images and see if everything will work as intended.
.d-flex {
display: flex;
}
.flex-row {
flex-direction: row;
}
.flex-column {
flex-direction: column;
}
.m-20 {
margin: 20px;
}
.mtr-20 {
margin: 20px 20px 0 0;
}
.mtrb-20 {
margin: 20px 20px 20px 0;
}
<div class="d-flex flex-row">
<div class="m-20"><img src="https://via.placeholder.com/150x220.png"/></div>
<div class="d-flex flex-column">
<div class="mtr-20"><img src="https://via.placeholder.com/150x100.png"/></div>
<div class="mtrb-20"><img src="https://via.placeholder.com/150x100.png"/></div>
</div>
<div class="d-flex flex-column">
<div class="mtr-20"><img src="https://via.placeholder.com/150x100.png"/></div>
<div class="mtrb-20"><img src="https://via.placeholder.com/150x100.png"/></div>
</div>
</div>
Now we notice that the images aren't quite aligned even though we've been very careful to get it pixel perfect. This is because images are display: inline by default and you can read all about those affects on the question Image inside div has extra space below the image.
So instead of inline we'll set them to flex.
.d-flex {
display: flex;
}
.flex-row {
flex-direction: row;
}
.flex-column {
flex-direction: column;
}
.m-20 {
margin: 20px;
}
.mtr-20 {
margin: 20px 20px 0 0;
}
.mtrb-20 {
margin: 20px 20px 20px 0;
}
img {
display: flex;
}
<div class="d-flex flex-row">
<div class="m-20"><img src="https://via.placeholder.com/150x220.png"/></div>
<div class="d-flex flex-column">
<div class="mtr-20"><img src="https://via.placeholder.com/150x100.png"/></div>
<div class="mtrb-20"><img src="https://via.placeholder.com/150x100.png"/></div>
</div>
<div class="d-flex flex-column">
<div class="mtr-20"><img src="https://via.placeholder.com/150x100.png"/></div>
<div class="mtrb-20"><img src="https://via.placeholder.com/150x100.png"/></div>
</div>
</div>

Combining the look of flex-start and space-between [duplicate]

This question already has answers here:
Targeting flex items on the last or specific row
(10 answers)
Wrapping flex items in the last row [duplicate]
(1 answer)
Closed 3 years ago.
I have a list of items I want to display with CSS. Originally, it was only two items side-by-side on one line but now I want to make it responsive for larger screens so I want to make it display 3 items on one line instead. My old code looks like this with justify-content:space-between. It looks good with an odd number of items to display.
.flex-container-old{
margin-top: 50px;
background: magenta;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.box-old{
width: 40%;
border: 1px solid black;
margin-bottom: 20px;
height: 300px;
background: orange;
}
.wrapper{
margin: 0 auto;
width: 80%;
}
body{
background:#D3D3D3;
}
<div class="wrapper">
<div class="flex-container-old">
<div class="box-old">
</div>
<div class="box-old">
</div>
<div class="box-old">
</div>
<div class="box-old">
</div>
<div class="box-old">
</div>
</div>
</div>
So naturally I extended it to three items in one row by modifying the width property only to end up with the below.
.flex-container-new{
background: lightblue;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.box {
width: 30%;
border: 1px solid black;
margin-bottom: 20px;
height: 300px;
background: orange;
}
.wrapper{
margin: 0 auto;
width: 80%;
}
<div class="wrapper">
<div class="flex-container-new">
<div class="box">
</div>
<div class="box">
</div>
<div class="box">
</div>
<div class="box">
</div>
<div class="box">
</div>
</div>
</div>
My problem in the case of the above code with three items on one line is I want the last item in last row to be pushed to the left, aligned with the middle item in the row above it. Sadly bootstrap is not an option. This is for learning purposes. It there a way I can achieve the above with just CSS? Many thanks in advance.
This is easier to control using CSS Grid because we can dictate both the x and y axis. With Flexbox, you can only reliably control the x axis. If you haven't heard about the fr unit, it's defined by Mozilla as follows:
The fr, which is short for “fraction”, is a unit which represents a fraction of the available space in the grid container.
Another nice thing about using Grid is that we can drop the height and margin-bottom set in .box and also the flex-wrap rule. Everything about the layout of this grid, from the height of the cells to the grid-gap spacing between them, is all defined in the parent.
.grid-container-new {
background: lightblue;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 300px);
grid-gap: 20px;
}
.box {
border: 1px solid black;
background: orange;
}
<div class="grid-container-new">
<div class="box">
</div>
<div class="box">
</div>
<div class="box">
</div>
<div class="box">
</div>
<div class="box">
</div>
</div>
jsFiddle

How to perfectly center grid-items while using CSS Grid auto-fit property? [duplicate]

This question already has answers here:
Aligning grid items across the entire row/column (like flex items can)
(3 answers)
Closed 4 years ago.
I have this Grid:
You can see the full code in Codepen
The problem is that, due to auto-fit property, when changing screen size, some columns go down. I need that even if new rows appear, all the grid items should be centered in the grid container.
This is the scenario:
body {margin: 0}
.about-us__block {
width: 150px;
height: 200px;
background: yellow;
}
.about-us__container {
background: black;
padding: 20px 0;
display: grid;
justify-items: center;
align-items: center;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
grid-gap: 10px;
}
.about-us__text {
padding: 5px;
text-align: center;
background-color: #35306B;
color: #ebecec;
}
.about-us__text h6 {
font-size: 1.5rem;
font-weight: 600;
margin: 0;
}
.about-us__text p {
font-family: Helvetica;
margin: 0;
}
.about-us__item:nth-of-type(4) {
grid-column: 2;
}
<div class="about-us__container">
<div class="about-us__item">
<div class="about-us__block"></div>
<div class="about-us__text">
<h6>John Doe</h6>
<p>BlaBla</p>
</div>
</div>
<div class="about-us__item">
<div class="about-us__block"></div>
<div class="about-us__text">
<h6>John Doe</h6>
<p>BlaBla</p>
</div>
</div>
<div class="about-us__item">
<div class="about-us__block"></div>
<div class="about-us__text">
<h6>John Doe</h6>
<p>BlaBla</p>
</div>
</div>
<div class="about-us__item">
<div class="about-us__block"></div>
<div class="about-us__text">
<h6>John Doe</h6>
<p>BlaBla</p>
</div>
</div>
</div>
I'm trying a lot of solutions, but none of them works.
I tried forcing the fourth grid-item to place in the 2nd column, but this occurs:
I had this same layout on my project.
On the container try:
display: flex;
flex-wrap: wrap;
justify-content: center;

How can I get even heights of unknown elements inside a column? [duplicate]

This question already has answers here:
Equal height flex items in flex columns
(3 answers)
Closed 5 years ago.
I'm using flex to create even columns and vh to make them the same height. That's working fine but inside the columns I can have an x number of items in them. I'd like for elements in each column to be even height depending on how many items are present (using css).
1 = 100%
2 = 50%
3 = 33.33%
etc.
I know I can do this through JS but I'd like to automate this through css via flex, grid, or something elese.
I've tried replicating your problem. Use flex: 1 on .items so that each and every item take equal space (according to the problem statement).
Have a look at the snippet below:
body {
margin: 0;
}
.parent {
width: 80%;
padding: 20px;
display: flex;
border: 1px solid red;
}
.child {
flex: 1;
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: flex-end;
padding: 20px;
border: 1px solid blue;
height: 60vh;
}
.item {
flex: 1;
background: lightGreen;
border: 1px solid green;
}
<div class="parent">
<div class="child">
<div class="item">33.33%</div>
<div class="item">33.33%</div>
<div class="item">33.33%</div>
</div>
<div class="child">
<div class="item">50%</div>
<div class="item">50%</div>
</div>
<div class="child">
<div class="item">100%</div>
</div>
</div>
Hope this is what you are trying to achieve.
This is all you need to make it work with the Flexbox:
.flex-container {
display: flex;
}
.flex-item {
display: flex;
flex-direction: column;
flex: 1;
}
.item {
flex: 1;
border: 1px solid;
}
<div class="flex-container">
<div class="flex-item">
<div class="item">1/1</div>
</div>
<div class="flex-item">
<div class="item">1/2</div>
<div class="item">1/2</div>
</div>
<div class="flex-item">
<div class="item">1/3</div>
<div class="item">1/3</div>
<div class="item">1/3</div>
</div>
<div class="flex-item">
<div class="item">1/4</div>
<div class="item">1/4</div>
<div class="item">1/4</div>
<div class="item">1/4</div>
</div>
</div>