Using margin on flex items - css

I was under the impression that a margin can be added to flex items/children, and flexbox should automatically take that into account and calculate the correct spacing between the items.
I can't seem to get this working as I would like though.
Fiddle here: https://jsfiddle.net/dba5ehcw/1/
.flex-item{
border: 1px solid blue;
box-sizing: border-box;
height: 160px;
width: 50%;
}
So each flex item at the moment is half the width of the container, and they flow nicely next to each other.
I would like to be able to add a margin of say, 1em to the flex-items in order to give them some breathing room, but in doing so, they become larger than the 50% and no longer stack next to each other on the same line because they are too wide.
Is there a way to use margin on the flex-items and have the flexbox container take this into account and adjust (decrease) their widths accordingly?

There are multiple ways to do this:
Use calc:
.flex-item {
width: calc(50% - 2em);
margin: 1em;
}
.flex-container {
border: 1px solid red;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
width: 320px;
}
.flex-item {
border: 1px solid blue;
box-sizing: border-box;
height: calc(160px - 2em);
width: calc(50% - 2em);
margin: 1em;
}
<div class="flex-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>
<div class="flex-item"></div>
</div>
Use nested boxes:
.flex-item {
width: 50%;
display: flex;
}
.flex-item > div {
border: 1px solid blue;
flex: 1;
margin: 1em;
}
.flex-container {
border: 1px solid red;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
width: 320px;
}
.flex-item {
height: 160px;
width: 50%;
display: flex;
}
.flex-item > div {
border: 1px solid blue;
flex: 1;
margin: 1em;
}
<div class="flex-container">
<div class="flex-item"><div></div></div>
<div class="flex-item"><div></div></div>
<div class="flex-item"><div></div></div>
<div class="flex-item"><div></div></div>
<div class="flex-item"><div></div></div>
<div class="flex-item"><div></div></div>
</div>
Place each row in a nowrap container, and use a positive flex-shrink factor
.row {
display: flex;
}
.flex-item {
width: 50%;
margin: 1em;
}
.flex-container {
border: 1px solid red;
width: 320px;
}
.row {
height: 160px;
display: flex;
}
.flex-item {
border: 1px solid blue;
width: 50%;
margin: 1em;
}
<div class="flex-container">
<div class="row">
<div class="flex-item"></div>
<div class="flex-item"></div>
</div>
<div class="row">
<div class="flex-item"></div>
<div class="flex-item"></div>
</div>
<div class="row">
<div class="flex-item"></div>
<div class="flex-item"></div>
</div>
</div>
Don't use width. Instead, force line-breaks at the right places, and use flex: 1 to make the elements grow to fill remaining space.
.flex-item {
flex: 1;
}
.line-break {
width: 100%
}
.flex-container {
border: 1px solid red;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
width: 320px;
}
.flex-item {
border: 1px solid blue;
box-sizing: border-box;
height: calc(160px - 2em);
flex: 1;
margin: 1em;
}
.line-break {
width: 100%;
}
<div class="flex-container">
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="line-break"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="line-break"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
</div>

You need to do it with padding - which, when in border-box mode does not make the container larger than it's specified width - not margin, and a nested flex div. This is how all flexbox-based grid systems work. Code below:
.flex-container{
border: 1px solid red;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
width: 320px;
}
.flex-item{
padding:1em;
box-sizing: border-box;
height: 160px;
width: 50%;
display:flex;
}
.flex-item>div {
border: 1px solid blue;
flex: 1 1 auto;
}
<div class="flex-container">
<div class="flex-item"><div></div></div>
<div class="flex-item"><div></div></div>
<div class="flex-item"><div></div></div>
<div class="flex-item"><div></div></div>
<div class="flex-item"><div></div></div>
<div class="flex-item"><div></div></div>
</div>

instead of using margins, try adding a gap on your flex container
.flex-container {
display: flex;
gap: 1em
}
flex-item {
width 50%
}

Try this : -
.flex-container {
border: 1px solid red;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
width: 320px;
}
.flex-item {
justify-content: space-around;
margin: 1%;
background: red;
border: 1px solid blue;
box-sizing: border-box;
height: 160px;
width: 48%;
}
<div class="flex-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>
<div class="flex-item"></div>
</div>

I believe I was trying to achieve the same thing, from my understanding, with the addition that I wanted the two boxes to stack on top of each other when the viewport gets small enough (when viewing on mobile/tablet).
For some reason I thought this would be way easier as I saw something similar in a Bootstrap tutorial video I watched but I think he was using row and col classes, with a g gutter class, and not Flex.
Anyway, HTML:
<div class="d-flex flex-wrap flex-half-screen-responsive">
<div class="col-lg-6">
Lorem Ipsum
</div>
<div class="col-lg-6">
Lorem Ipsum
</div>
</div>
CSS:
.flex-half-screen-responsive {
margin: -0.5em;
}
.flex-half-screen-responsive > * {
flex: 1 1 48%;
margin: 0.5em;
}
I don't like how I have to specify that hardcoded 48% value but it seems to work just as I want it so whatever; spent way too much time on this already lol. Anyway I hope this helps someone looking for the same behavior.

Related

Positioning of elements in a flex layout [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I need help laying out my html with css flexbox (I hope this is doable with flexbox).
I have a Container with a variable amount of images. Image can be either landscape or portrait orientation. If image is landscape (Image 1) - it will occupy one 'row'. If image is portrait - there are two cases:
If there is one portrait image in a 'row' (either it's the last image, or the next one is landscape) - then Image 2 should be centered on the 'row'.
If there are two successive portrait images - I'd like them to both fit into one 'row'
Pls note, that the 'rows' are an abstract notion here. I don't want to use css grid (unless there are absolutely no other options).
Using a flexbox in combination with the justify-content: center; and flex-wrap: wrap; should achieve the exact effect you are looking for.
Please see the two code snippets below for the two examples. I have used multiple coloured div with a width and height to simulate the horizontal and vertical image types you referred to.
.flex {
display: flex;
flex-wrap: wrap;
width: 100px;
border: 2px black solid;
padding: 1em;
justify-content: center;
}
.horizontal {
background: yellow;
width: 100px;
height: 50px;
margin-bottom: 1em;
}
.vertical {
background: green;
width: 50px;
height: 100px;
}
<div class="flex">
<div class="horizontal">Image 1</div>
<div class="vertical">Image 2</div>
</div>
.flex {
display: flex;
flex-wrap: wrap;
width: 100px;
border: 2px black solid;
padding: 1em;
justify-content: center;
}
.horizontal {
background: yellow;
width: 100px;
height: 50px;
margin-bottom: 1em;
}
.vertical {
background: green;
width: 50px;
height: 100px;
}
#blue {
background: blue;
}
<div class="flex">
<div class="horizontal">Image 1</div>
<div class="vertical">Image 2</div>
<div class="vertical" id="blue">Image 3</div>
</div>
This can be done with align-items: center and flex-wrap:wrap:
.flex{
width: 220px;
display:flex;
align-items: center;
flex-wrap:wrap;
}
.flex img{
border: solid 4px #efefef;
box-sizing:border-box;
margin: 0 auto;
}
<h3>Example 1</h3>
<div class="flex">
<img src="https://placekitten.com/220/60">
<img src="https://placekitten.com/110/120">
</div>
<h3>Example 2</h3>
<div class="flex">
<img src="https://placekitten.com/220/60">
<img src="https://placekitten.com/100/120">
<img src="https://placekitten.com/100/120">
</div>
You can easily achieve this using the same grid system as Bootstrap using class like container, row, col:
.container {
display: flex;
flex-direction: column;
}
.row {
display: flex;
}
.align-center {
align-items: center;
justify-content: center;
}
.image1 {
width: 500px;
height: 300px;
background-color: red;
}
.image2,
.image3 {
width: 250px;
height: 500px;
}
.image2 {
background-color: yellow;
}
.image3 {
background-color: blue;
}
.image1,
.image2,
.image3 {
border: solid #000 2px;
}
<div class="container align-center">
<div class="row">
<div class="col image1">
<h1>image1</h1>
</div>
</div>
<div class="row align-center">
<div class="col image2">
<h1>image2</h1>
</div>
</div>
</div>
<div class="container align-center">
<div class="row">
<div class="col image1">
<h1>image1</h1>
</div>
</div>
<div class="row align-center">
<div class="col image2">
<h1>image2</h1>
</div>
<div class="col image3">
<h1>image3</h1>
</div>
</div>
</div>

CSS flex-wrap how to make the height do not stretch [duplicate]

This question already has answers here:
CSS-only masonry layout
(4 answers)
Closed 3 years ago.
There are big gaps between box3, box1 and box4, box6 How to get rid of the gap? so each box could have the dynamic height?
.wrap {
display: flex;
align-items: baseline;
align-content:flex-start;
justify-content: space-between;
flex-wrap: wrap;
background-color: lightblue;
}
.box {
display: flex;
background-color: tomato;
box-sizing: border-box;
border: 1px solid #C4C4C4;
height: 100px;
width: 45%;
margin-top: 15px;
}
.box1, .box4 {
height: 20px;
}
<div class="wrap">
<div class="box box1">box1</div>
<div class="box box2">box2</div>
<div class="box box3">box3</div>
<div class="box box4">box4</div>
<div class="box box5">box5</div>
<div class="box box6">box6</div>
</div>
Here is the desired layout. Thanks
The default direction of flex is row, and when you use flex-wrap: wrap push overflowed element downed to another row, and the row height will default always equal to the highest element of that row, that why you seeing the element having that gap.
This can be done if you change the flex direction to column and give the wrap element a fixed height so it push overflowed element to it right, from top to bottom.
.wrap {
/*Added these*/
height: 300px;
flex-direction: column;
/*-----------*/
display: flex;
align-items: baseline;
align-content: space-around;
flex-wrap: wrap;
background-color: lightblue;
}
.box {
display: flex;
background-color: tomato;
box-sizing: border-box;
border: 1px solid #C4C4C4;
height: 100px;
width: 45%;
margin-top: 15px;
}
.box1, .box5 {
height: 20px;
}
<div class="wrap">
<div class="box box1">box1</div>
<div class="box box2">box2</div>
<div class="box box3">box3</div>
<div class="box box4">box4</div>
<div class="box box5">box5</div>
<div class="box box6">box6</div>
</div>
Since FlexBox is going to attempt to line the boxes up in rows, you have to create two separate FlexBoxes with flex-flow: column set. You can achieve this affect with about the same amount of CSS though:
.outer{
display: flex;
padding: 15px 0;
background-color: lightblue;
}
.wrap {
display: flex;
flex-flow: column;
flex-grow: 1;
}
.wrap:nth-child(2){
align-items: flex-end;
}
.box {
background-color: tomato;
box-sizing: border-box;
border: 1px solid #C4C4C4;
height: 100px;
width: 90%;
margin-top: 15px;
}
.box1, .box4{
margin-top: 0;
}
.box1, .box5 {
height: 20px;
}
<div class="outer">
<div class="wrap">
<div class="box box1">box1</div>
<div class="box box2">box2</div>
<div class="box box3">box3</div>
</div>
<div class="wrap">
<div class="box box4">box4</div>
<div class="box box5">box5</div>
<div class="box box6">box6</div>
</div>
</div>
You could instead use a CSS grid layout depending on your browser support requirements.
Great resource on CSS Grid: https://css-tricks.com/snippets/css/complete-guide-grid/
Browser support: https://caniuse.com/#feat=css-grid
.wrap {
display: grid;
background-color: lightblue;
grid-template-columns: 50% 50%;
grid-template-rows: repeat(14, 20px);
background-color: lightblue;
}
.box {
background-color: tomato;
box-sizing: border-box;
border: 1px solid #C4C4C4;
height: 100px;
width: 90%;
margin-top: 15px;
}
.box1 {
grid-row: 1/2;
}
.box2 {
grid-row: 1/5;
}
.box3 {
grid-row: 3/8;
}
.box4 {
grid-row: 7/8;
}
.box5, .box6 {
grid-row: 9/14;
}
.box1, .box4 {
height: 20px;
}
<div class="wrap">
<div class="box box1">box1</div>
<div class="box box2">box2</div>
<div class="box box3">box3</div>
<div class="box box4">box4</div>
<div class="box box5">box5</div>
<div class="box box6">box6</div>
</div>
Flex is always going to create a grid which is why you're seeing big spaces. Neither flex:row or flex:column will achieve the order that you have specified. Flex column will be able to achieve the layout that you're after like Ethan Vu suggested but that main caveat in that solution is a mandatory fixed height container which you may not want.
If you want a layout like that and don't want a fixed height then you can try using css columns or go for a javascript solution and use a 2 column masonry layout.

Empty cell in flexbox

There is a usual flexbox with the elements:
.flexbox {
display: flex;
border: 2px solid red;
padding: 2.5px;
}
.flexbox__item {
border: 2px solid blue;
height: 50px;
margin: 2.5px;
flex-grow: 1;
}
<div class="flexbox">
<div class="flexbox__item"></div>
<div class="flexbox__item offset-1"></div>
<div class="flexbox__item"></div>
</div>
How to insert an empty cell in this flexbox after .offset-* without using additional markup and after with before?
Those. It is necessary that it come out like this, but without specifying the width of the blocks. Only flex-grow
.flexbox {
display: flex;
border: 2px solid red;
padding: 2.5px;
}
.flexbox__item {
border: 2px solid blue;
height: 50px;
margin: 2.5px;
width: 25%;
}
.offset-1 {
margin-right: calc(25% + 5px);
}
<div class="flexbox">
<div class="flexbox__item"></div>
<div class="flexbox__item offset-1"></div>
<div class="flexbox__item"></div>
</div>
The number of cells is unknown. Offset-1 means that you need to make an empty one cell,offset-2 means two cell, and so on.
It is possible with additional wrappers - the wrappers will grow, and the cell elements inside the growing wrappers will occupy 1/2, 1/3, etc. of the width of the wrappers.
.flexbox {
display: flex;
border: 2px solid red;
padding: 3px;
}
.flexbox__item {
margin: 3px;
flex-grow: 1;
}
.flexbox__item-inner {
border: 2px solid blue;
height: 50px;
}
.offset-1 {
flex-grow: 2;
}
.offset-1 .flexbox__item-inner {
width: 50%;
}
.offset-2 {
flex-grow: 3;
}
.offset-2 .flexbox__item-inner {
width: 33.33%;
}
<div class="flexbox">
<div class="flexbox__item">
<div class="flexbox__item-inner"></div>
</div>
<div class="flexbox__item offset-1">
<div class="flexbox__item-inner"></div>
</div>
<div class="flexbox__item">
<div class="flexbox__item-inner"></div>
</div>
</div>
<div class="flexbox">
<div class="flexbox__item">
<div class="flexbox__item-inner"></div>
</div>
<div class="flexbox__item offset-2">
<div class="flexbox__item-inner"></div>
</div>
<div class="flexbox__item">
<div class="flexbox__item-inner"></div>
</div>
</div>

Aligning flex items to the flex-end

Hei,
I'm creating grid layout and when trying to align items on flex-end or start, height/width becomes zero.
What I'm wondering is, is it possible to align items in flex container to the top/bottom/center WITHOUT specifying height/width? In my case I didn't specify any height and it doesn't work. If I specify it, it works. Line that doesn't work is commented in first example.
Here is code:
.flex-container {
display: flex;
background: silver;
width: 400px;
height: 200px;
//align-items: flex-start;
}
.flex-item {
background: blue;
flex: 1 0 10px;
margin: 5px;
}
.flex-container2 {
display: flex;
background: silver;
width: 400px;
height: 200px;
align-items: flex-end;
}
.flex-item2 {
background: blue;
height: 50px;
flex: 1 0 10px;
margin: 5px;
}
<div class="flex-container">
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
</div>
<br>
<div class="flex-container2">
<div class="flex-item2"></div>
<div class="flex-item2"></div>
<div class="flex-item2"></div>
<div class="flex-item2"></div>
</div>
As the default value for align-items is stretch, hence they fill their parents height, and you change it to flex-start/flex-end, the row flex items becomes 0 in height, and will need content (or a height/min-height) for you to actually see them.
.flex-container {
display: flex;
background: silver;
width: 400px;
height: 200px;
align-items: flex-start;
}
.flex-item {
background: blue;
min-height: 20px;
flex: 1 0 10px;
margin: 5px;
}
.flex-item:nth-child(even) {
align-self: flex-end;
}
.flex-container2 {
display: flex;
background: silver;
width: 400px;
height: 200px;
align-items: flex-end;
}
.flex-item2 {
background: blue;
height: 50px;
flex: 1 0 10px;
margin: 5px;
}
<div class="flex-container">
<div class="flex-item">They need content or a height/min-height</div>
<div class="flex-item">They need content or a height/min-height</div>
<div class="flex-item"></div>
<div class="flex-item"></div>
</div>
<br>
<div class="flex-container2">
<div class="flex-item2"></div>
<div class="flex-item2"></div>
<div class="flex-item2"></div>
<div class="flex-item2"></div>
</div>

How can I make flexbox wrap only an even number of items? [duplicate]

Is there a way to make a line break in multiple line flexbox?
For example to break after each 3rd item in this CodePen.
.container {
background: tomato;
display: flex;
flex-flow: row wrap;
align-content: space-between;
justify-content: space-between;
}
.item {
width: 100px;
height: 100px;
background: gold;
border: 1px solid black;
font-size: 30px;
line-height: 100px;
text-align: center;
margin: 10px;
}
.item:nth-child(3n) {
background: silver;
}
<div class="container">
<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 class="item">10</div>
</div>
Like
.item:nth-child(3n){
/* line-break: after; */
}
The simplest and most reliable solution is inserting flex items at the right places. If they are wide enough (width: 100%), they will force a line break.
.container {
background: tomato;
display: flex;
flex-flow: row wrap;
align-content: space-between;
justify-content: space-between;
}
.item {
width: 100px;
background: gold;
height: 100px;
border: 1px solid black;
font-size: 30px;
line-height: 100px;
text-align: center;
margin: 10px
}
.item:nth-child(4n - 1) {
background: silver;
}
.line-break {
width: 100%;
}
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="line-break"></div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="line-break"></div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="line-break"></div>
<div class="item">10</div>
</div>
But that's ugly and not semantic. Instead, we could generate pseudo-elements inside the flex container, and use order to move them to the right places.
.container {
background: tomato;
display: flex;
flex-flow: row wrap;
align-content: space-between;
justify-content: space-between;
}
.item {
width: 100px;
background: gold;
height: 100px;
border: 1px solid black;
font-size: 30px;
line-height: 100px;
text-align: center;
margin: 10px
}
.item:nth-child(3n) {
background: silver;
}
.container::before, .container::after {
content: '';
width: 100%;
order: 1;
}
.item:nth-child(n + 4) {
order: 1;
}
.item:nth-child(n + 7) {
order: 2;
}
<div class="container">
<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>
But there is a limitation: the flex container can only have a ::before and a ::after pseudo-element. That means you can only force 2 line breaks.
To solve that, you can generate the pseudo-elements inside the flex items instead of in the flex container. This way you won't be limited to 2. But those pseudo-elements won't be flex items, so they won't be able to force line breaks.
But luckily, CSS Display L3 has introduced display: contents (currently only supported by Firefox 37):
The element itself does not generate any boxes, but its children and
pseudo-elements still generate boxes as normal. For the purposes of
box generation and layout, the element must be treated as if it had
been replaced with its children and pseudo-elements in the document
tree.
So you can apply display: contents to the children of the flex container, and wrap the contents of each one inside an additional wrapper. Then, the flex items will be those additional wrappers and the pseudo-elements of the children.
.container {
background: tomato;
display: flex;
flex-flow: row wrap;
align-content: space-between;
justify-content: space-between;
}
.item {
display: contents;
}
.item > div {
width: 100px;
background: gold;
height: 100px;
border: 1px solid black;
font-size: 30px;
line-height: 100px;
text-align: center;
margin: 10px;
}
.item:nth-child(3n) > div {
background: silver;
}
.item:nth-child(3n)::after {
content: '';
width: 100%;
}
<div class="container">
<div class="item"><div>1</div></div>
<div class="item"><div>2</div></div>
<div class="item"><div>3</div></div>
<div class="item"><div>4</div></div>
<div class="item"><div>5</div></div>
<div class="item"><div>6</div></div>
<div class="item"><div>7</div></div>
<div class="item"><div>8</div></div>
<div class="item"><div>9</div></div>
<div class="item"><div>10</div></div>
</div>
Alternatively, according to an old version of the spec, Flexbox allowed forced breaks by using break-before, break-after or their old CSS 2.1 aliases:
.item:nth-child(3n) {
page-break-after: always; /* CSS 2.1 syntax */
break-after: always; /* CSS 3 syntax */
}
But these forced line breaks only work on Firefox, and I don't think they are supposed to work according to the current spec. The new proposed way (not implemented anywhere) is with wrap-before or wrap-after:
.item:nth-child(3n) {
wrap-after: flex; /* New proposed syntax */
}
.container {
background: tomato;
display: flex;
flex-flow: row wrap;
align-content: space-between;
justify-content: space-between;
}
.item {
width: 100px;
background: gold;
height: 100px;
border: 1px solid black;
font-size: 30px;
line-height: 100px;
text-align: center;
margin: 10px
}
.item:nth-child(3n) {
page-break-after: always;
break-after: always;
wrap-after: flex;
background: silver;
}
<div class="container">
<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 class="item">10</div>
</div>
From my perspective it is more semantic to use <hr> elements as line breaks between flex items.
.container {
display: flex;
flex-flow: wrap;
}
.container hr {
width: 100%;
}
<div class="container">
<div>1</div>
<div>2</div>
<hr>
<div>3</div>
<div>2</div>
...
</div>
Tested in Chrome 66, Firefox 60 and Safari 11.
#Oriol has an excellent answer, sadly as of October 2017, neither display:contents, neither page-break-after is widely supported, better said it's about Firefox which supports this but not the other players, I have come up with the following "hack" which I consider better than hard coding in a break after every 3rd element, because that will make it very difficult to make the page mobile friendly.
As said it's a hack and the drawback is that you need to add quite a lot of extra elements for nothing, but it does the trick and works cross browser even on the dated IE11.
The "hack" is to simply add an additional element after each div, which is set to display:none and then used the css nth-child to decide which one of this should be actually made visible forcing a line brake like this:
.container {
background: tomato;
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.item {
width: 100px;
background: gold;
height: 100px;
border: 1px solid black;
font-size: 30px;
line-height: 100px;
text-align: center;
margin: 10px
}
.item:nth-child(3n-1) {
background: silver;
}
.breaker {
display: none;
}
.breaker:nth-child(3n) {
display: block;
width: 100%;
height: 0;
}
<div class="container">
<div class="item">1</div>
<p class="breaker"></p>
<div class="item">2</div>
<p class="breaker"></p>
<div class="item">3</div>
<p class="breaker"></p>
<div class="item">4</div>
<p class="breaker"></p>
<div class="item">5</div>
<p class="breaker"></p>
<div class="item">6</div>
<p class="breaker"></p>
<div class="item">7</div>
<p class="breaker"></p>
<div class="item">8</div>
<p class="breaker"></p>
<div class="item">9</div>
<p class="breaker"></p>
<div class="item">10</div>
<p class="breaker"></p>
</div>
You want a semantic linebreak?
Then consider using <br>. W3Schools may suggest you that BR is just for writing poems (mine is coming soon) but you can change the style so it behaves as a 100% width block element that will push your content to the next line. If 'br' suggests a break then it seems more appropriate to me than using hr or a 100% div and makes the html more readable.
Insert the <br> where you need linebreaks and style it like this.
// Use `>` to avoid styling `<br>` inside your boxes
.container > br
{
width: 100%;
content: '';
}
You can disable <br> with media queries, by setting display: to block or none as appropriate (I've included an example of this but left it commented out).
You can use order: to set the order if needed too.
And you can put as many as you want, with different classes or names :-)
.container {
background: tomato;
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.item {
width: 100px;
background: gold;
height: 100px;
border: 1px solid black;
font-size: 30px;
line-height: 100px;
text-align: center;
margin: 10px
}
.container > br
{
width: 100%;
content: '';
}
// .linebreak1
// {
// display: none;
// }
// #media (min-width: 768px)
// {
// .linebreak1
// {
// display: block;
// }
// }
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<br class="linebreak1"/>
<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 class="item">10</div>
</div>
No need to limit yourself to what W3Schools says:
I think the traditional way is flexible and fairly easy to understand:
Markup
<div class="flex-grid">
<div class="col-4">.col-4</div>
<div class="col-4">.col-4</div>
<div class="col-4">.col-4</div>
<div class="col-4">.col-4</div>
<div class="col-4">.col-4</div>
<div class="col-4">.col-4</div>
<div class="col-3">.col-3</div>
<div class="col-9">.col-9</div>
<div class="col-6">.col-6</div>
<div class="col-6">.col-6</div>
</div>
Create grid.css file:
.flex-grid {
display: flex;
flex-flow: wrap;
}
.col-1 {flex: 0 0 8.3333%}
.col-2 {flex: 0 0 16.6666%}
.col-3 {flex: 0 0 25%}
.col-4 {flex: 0 0 33.3333%}
.col-5 {flex: 0 0 41.6666%}
.col-6 {flex: 0 0 50%}
.col-7 {flex: 0 0 58.3333%}
.col-8 {flex: 0 0 66.6666%}
.col-9 {flex: 0 0 75%}
.col-10 {flex: 0 0 83.3333%}
.col-11 {flex: 0 0 91.6666%}
.col-12 {flex: 0 0 100%}
[class*="col-"] {
margin: 0 0 10px 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#media (max-width: 400px) {
.flex-grid {
display: block;
}
}
I've created an example (jsfiddle)
Try to resize the window under 400px, it's responsive!!
I just want to throw this answer in the mix, intended as a reminder that – given the right conditions – you sometimes don't need to overthink the issue at hand. What you want might be achievable with flex: wrap and max-width instead of :nth-child.
ul {
display: flex;
flex-wrap: wrap;
justify-content: center;
max-width: 420px;
list-style-type: none;
background-color: tomato;
margin: 0 auto;
padding: 0;
}
li {
display: inline-block;
background-color: #ccc;
border: 1px solid #333;
width: 23px;
height: 23px;
text-align: center;
font-size: 1rem;
line-height: 1.5;
margin: 0.2rem;
flex-shrink: 0;
}
<div class="root">
<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>L</li>
<li>M</li>
<li>N</li>
<li>O</li>
<li>P</li>
<li>Q</li>
<li>R</li>
<li>S</li>
<li>T</li>
<li>U</li>
<li>V</li>
<li>W</li>
<li>X</li>
<li>Y</li>
<li>Z</li>
</ul>
</div>
https://jsfiddle.net/age3qp4d/
Another possible solution that doesn't require to add any extra markup is to add some dynamic margin to separate the elements.
In the case of the example, this can be done with the help of calc(), just adding margin-left and margin-right to the 3n+2 element (2, 5, 8)
.item:nth-child(3n+2) {
background: silver;
margin: 10px calc(50% - 175px);
}
Snippet Example
.container {
background: tomato;
display: flex;
flex-flow: row wrap;
align-content: space-between;
justify-content: space-between;
}
.item {
width: 100px;
height: 100px;
background: gold;
border: 1px solid black;
font-size: 30px;
line-height: 100px;
text-align: center;
margin: 10px;
}
.item:nth-child(3n+2) {
background: silver;
margin: 10px calc(50% - 175px);
}
<div class="container">
<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 class="item">10</div>
</div>
For future questions, It's also possible to do it by using float property and clearing it in each 3 elements.
Here's an example I've made.
.grid {
display: inline-block;
}
.cell {
display: inline-block;
position: relative;
float: left;
margin: 8px;
width: 48px;
height: 48px;
background-color: #bdbdbd;
font-family: 'Helvetica', 'Arial', sans-serif;
font-size: 14px;
font-weight: 400;
line-height: 20px;
text-indent: 4px;
color: #fff;
}
.cell:nth-child(3n) + .cell {
clear: both;
}
<div class="grid">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell">6</div>
<div class="cell">7</div>
<div class="cell">8</div>
<div class="cell">9</div>
<div class="cell">10</div>
</div>
.container {
background: tomato;
display: flex;
flex-flow: row wrap;
align-content: space-between;
justify-content: space-between;
}
.item {
width: 100px;
height: 100px;
background: gold;
border: 1px solid black;
font-size: 30px;
line-height: 100px;
text-align: center;
margin: 10px;
}
<div class="container">
<div>
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
<div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
<div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
</div>
<div class="item">10</div>
</div>
you could try wrapping the items in a dom element like here. with this you dont have to know a lot of css just having a good structure will solve the problem.

Resources