CSS manage nested flexbox width by content priority - css

I struggling with flexbox wrapping.
I have this 2 levels list:
<div class="wrapper">
<div class="list list-1">
<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>
<div class="list list-2">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
<div class="item">E</div>
<div class="item">F</div>
</div>
<div class="item">★</div>
</div>
The HTML structure can be modified if its needed.
Base on wrapper width render should fit these rules:
mimic one list (same margin between all items);
The first item of all lists have to be visible;
but list-1 content has priority of list-2;
items only complete item can be visible in the list;
Render example:
1 A X
1 2 3 A X
1 2 3 4 5 6 7 8 9 A X
1 2 3 4 5 6 7 8 9 A B C D E F X
With my current achievement, I miss the priority wrapping (the both list get the same width and number of elements), and the spaces between items in both lists are not the same.
.wrapper {
display: flex;
flex-flow: row nowrap;
width: 100%;
height: 37px;
border-radius: 5px;
background-color: #222;
justify-content: flex-end;
}
.list {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.list div:not(:first-child) {
margin-left: 2px;
}
.item {
display: flex;
width: 45px;
height: 26px;
align-items: center;
justify-content: center;
margin: 4px 4px 10px;
color: #fff;
background-color: #3d3d3d;
}
Any idea are welcome!

You can add flex-shrink:0 to the first list so it will never shrink and you will have your priority rule and add min-width:0 to the other list to allow it to shrink when there isn't enough space. You should also allow the wrap so that you don't see half an element when it overflow.
With your new rule there will be a wrong space with the last element.
.wrapper {
display: flex;
flex-flow: row nowrap;
height: 37px;
border-radius: 5px;
background-color: #222;
justify-content: flex-end;
}
.list {
display: flex;
flex-wrap:wrap;
}
/*added this*/
.list-1 {
flex-shrink:0;
}
.list-2 {
min-width:0;
overflow:hidden;
}
/**/
.item {
display: flex;
width: 45px;
height: 26px;
align-items: center;
justify-content: center;
margin: 4px 4px 10px;
color: #fff;
background-color: #3d3d3d;
flex-shrink:0; /*this is also mandatory to avoid the item to shrink*/
}
<div class="wrapper">
<div class="list list-1">
<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>
<div class="list list-2">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
<div class="item">E</div>
<div class="item">F</div>
</div>
<div class="item">★</div>
</div>
Without overlfow here is a hack to hide the non needed element:
.wrapper {
display: flex;
flex-flow: row nowrap;
height: 37px;
border-radius: 5px;
background-color: #222;
justify-content: flex-end;
}
.list {
display: flex;
flex-wrap:wrap;
position:relative;
align-self: flex-start;
}
.list::after {
content:"";
position:absolute;
bottom:0;
top:37px;
left:0;
right:0;
background:#fff;
}
/*added this*/
.list-1 {
flex-shrink:0;
}
.list-2 {
min-width:0;
}
/**/
.item {
display: flex;
width: 45px;
height: 26px;
align-items: center;
justify-content: center;
margin: 4px 4px 10px;
color: #fff;
background-color: #3d3d3d;
flex-shrink:0; /*this is also mandatory to avoid the item to shrink*/
}
<div class="wrapper">
<div class="list list-1">
<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>
<div class="list list-2">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
<div class="item">E</div>
<div class="item">F</div>
</div>
<div class="item">★</div>
</div>

Related

How to break multiple divs in next line if can't fit [duplicate]

This question already has answers here:
Why are flex items not wrapping?
(2 answers)
Closed 10 months ago.
I want to put multiple divs in same row and if they cant fit to break to next line.I want this enter image description here instead of this enter image description here
.cardContainer {
display: flex;
}
.card {
min-width: 185.17px;
height: 88px;
border-radius: 8px;
background: red;
margin-right: 8px;
display: block;
}
<div className="cardContainer">
<div className="card">A</div>
<div className="card">A</div>
<div className="card">A</div>
<div className="card">A</div>
<div className="card">A</div>
<div className="card">A</div>
<div className="card">A</div>
</div>
CSS Flexbox would be your friend:
.cardContainer {
display: flex;
gap: 10px;
}
.card {
background-color: red;
color: white;
width:20%;
border-radius: 8px;
padding: 10px;
height: 100px;
}
<div class="cardContainer">
<div class="card">A</div>
<div class="card">A</div>
<div class="card">A</div>
<div class="card">A</div>
<div class="card">A</div>
<div class="card">A</div>
<div class="card">A</div>
</div>
.container {
display: flex;
flex-wrap: no-wrap;
gap: 10px 10px;
}
.item {
width: 20%;
height: 50px;
background-color: red;
}
<div class='container'>
<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>

Flexbox make columns equal heights

I am trying to get 3 columns in a row and be the same height.
I am using the HTML/CSS below. I can't figure out why the boxes arent the same height.
.container {
text-align: center;
display: block;
width: 100%;
}
.grid {
width: 100%;
height: 100%;
}
.row {
display: flex;
height: 100%;
flex-direction: row;
}
.col {
background: #444;
padding: 2em;
flex: 1;
height: 100%;
border: 1px solid blue;
}
<div class="container">
<div class="data">
<div class="grid">
<div class="row">
<div class="col">
<p>col 1</p>
</div>
<div class="col">
<p>col </br>2</p>
</div>
<div class="col">
<p>col 3</p>
</div>
</div>
</div>
</div>
</div>
How can I make the boxes all the same height. thanks
Simply, remove the height: 100% from .col.
flex: 1; will do the job.
.row {
display: flex;
}
.col {
flex: 1;
background: #444;
padding: 2em;
border: 1px solid blue;
text-align: center;
}
<div class="container">
<div class="data">
<div class="grid">
<div class="row">
<div class="col">
<p>col 1</p>
</div>
<div class="col">
<p>col </br>2</p>
</div>
<div class="col">
<p>col 3</p>
</div>
</div>
</div>
</div>
</div>

Flexbox: row with inline-flex + fixed item width (fixing flex-basis bug): not working inside column layout

I want to get a table in CSS with a sticky header (only body scrolls) on Y, and whole table scrolls on X.
According to Michael_B comment on my previous question here there is a flexbox bug and I have to use inline-flex on row + width on cells to make sure my row grows correctly.
This leads me to this result:
html, body {
width: 100%;
min-height: 100vh;
margin: 0;
padding: 0;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
.table {
border: solid black;
width: 60vw;
height: 80vh;
overflow-x: auto;
display: flex;
flex-direction: column;
}
.header {
border: solid cyan;
flex: 0;
}
.body {
flex: 1;
overflow-y: auto;
border: solid yellow;
display: inline-block;
}
.row {
border: solid red;
display: inline-flex;
flex-direction: row;
align-items: center;
}
.cell {
border: solid green;
width: 400px;
height: 50px;
}
<div class="table">
<div class="header">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
<div class="body">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
</div>
JsFiddle
As you can see it's not exactly what I want. It seems my rows do not grow according to their content size even with inline-flex, and this happens only when using a flex column layout on the table.
html, body {
width: 100%;
min-height: 100vh;
margin: 0;
padding: 0;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
.table {
border: solid black;
width: 60vw;
height: 80vh;
overflow-x: auto;
}
.header {
border: solid cyan;
flex: 0;
display: inline-block;
height: 50px;
}
.body {
flex: 1;
overflow-y: auto;
border: solid yellow;
display: inline-block;
height: calc(100% - 50px - 16px);
}
.row {
border: solid red;
display: inline-flex;
flex-direction: row;
align-items: center;
}
.cell {
border: solid green;
width: 400px;
height: 50px;
}
By removing flex column, using inline-block and calc computations, I almost get the behavior I want, except I'd like the scrollY scrollbar to always stay visible
<div class="table">
<div class="header">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
<div class="body">
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
<div class="row">
<div class="cell">
cell 1
</div>
<div class="cell">
cell 2
</div>
<div class="cell">
cell 3
</div>
</div>
</div>
</div>
JsFiddle
Anyone knows how I could achieve the table layout I want? I'm open for no flexbox solution but I don't want a JS based solution for now.

Strange Margin showing up in a flexbox

I have tried negative margins and other hacks but as far as i know, there shouldn't be any margins there in the first place. With just a simple box i can get zero margins between the tags but somehow the stuff outside that is messing with it.
The problem is with the neon blue badges in the bottom right corner.
.info{
display: flex;
flex-direction: row;
// justify-content: space-between;
}
.column {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 48%;
min-height: 61.9px;
// background-color: #00ffff;
display: flex;
flex-direction: column;
}
.info-block{
display: flex;
flex-direction: column;
}
.spacer{
height:14.7px;
width: 1px;
}
.tag{
line-height: 0;
display:inline-block;
height: 15.8px;
width:40px;
padding-right: 4px;
padding-left: 4px;
padding-top: 2px;
background-color: #00ffff;
border-radius: 4px;
}
.tag-container{
line-height: 0;
width: 168px;
height:78px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-content: flex-start;
}
.tag-text{
width:20px;
font-family: HelveticaNeue-Bold;
font-size: 8px;
font-weight: normal;
font-style: normal;
font-stretch: normal;
text-align: center;
color: #ffffff;
}
<div class="info">
<div class="column">
<div class="info-block">
<div class="info-header">Location</div>
<div class="info-text">place</div>
</div>
<div class="spacer"></div>
<div class="info-block">
<div class="info-header">Mobile</div>
<div class="info-text">+44 (0) 788-588</div>
</div>
</div>
<div class="column">
<div class="info-block">
<div class="info-header">Menu</div>
<div class="info-text"><a>bk.com</a></div>
</div>
<div class="spacer"></div>
<div class="info-block ">
<div class="info-header">Tags</div>
<div class="tag-containter">
<div class="tag"><div class="tag-text">h</div></div>
<div class="tag"><div class="tag-text">Som</div></div>
<div class="tag"><div class="tag-text">Somethg</div></div>
<div class="tag">
<div class="tag-text">ng</div>
</div>
<div class="tag">
<div class="tag-text">Somhing</div>
</div>
</div>
</div>
</div>
You only made a silly mistake.
Just check your class name .tag-containter in css and html.
you use .tag-container instead of tag-containter class.
you mispelled the class tag-container either in the html (tag-containter) or in the css . notice the extra T in html and missing in css selector
.info {
display: flex;
flex-direction: row;
/* justify-content: space-between;*/
}
.column {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 48%;
min-height: 61.9px;
/* background-color: #00ffff;*/
display: flex;
flex-direction: column;
}
.info-block {
display: flex;
flex-direction: column;
}
.spacer {
height: 14.7px;
width: 1px;
}
.tag {
line-height: 0;
height: 15.8px;
width: 40px;
padding-right: 4px;
padding-left: 4px;
padding-top: 2px;
background-color: #00ffff;
border-radius: 4px;
}
.tag-containter {
width: 168px;
height: 78px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-content: flex-start;
}
.tag-text {
font-family: HelveticaNeue-Bold;
font-size: 8px;
font-weight: normal;
font-style: normal;
font-stretch: normal;
text-align: center;
color: #ffffff;
}
<div class="info">
<div class="column">
<div class="info-block">
<div class="info-header">Location</div>
<div class="info-text">place</div>
</div>
<div class="spacer"></div>
<div class="info-block">
<div class="info-header">Mobile</div>
<div class="info-text">+44 (0) 788-588</div>
</div>
</div>
<div class="column">
<div class="info-block">
<div class="info-header">Menu</div>
<div class="info-text"><a>bk.com</a>
</div>
</div>
<div class="spacer"></div>
<div class="info-block ">
<div class="info-header">Tags</div>
<div class="tag-containter">
<div class="tag">
<div class="tag-text">h</div>
</div>
<div class="tag">
<div class="tag-text">Som</div>
</div>
<div class="tag">
<div class="tag-text">Somethg</div>
</div>
<div class="tag">
<div class="tag-text">ng</div>
</div>
<div class="tag">
<div class="tag-text">Somhing</div>
</div>
</div>
</div>
</div>
.tag is set to display: inline-block;, which is an inline element. Spaces between inline elements are preserved in HTML, so if you have spaces (or returns) between the elements, you will see a space between the elements on the page. To remove the spaces between the .tag boxes, remove the actual spaces between those elements.

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