When using space-around
as a param to justify-content
, it will space the items evenly within the container. What I'd like is for all the items to start (flex-start
) on the left but have the same margin that space-around
would offer.
I think this shows the issue:
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
width: 100%;
border: 1px solid red;
}
.item {
flex: 0 0 16%; /*6 items per line leaving some for margin*/
border: 1px solid black;
box-sizing: border-box;
}
<div class="container">
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
</div>
What I'd like is for the second line to wrap and take up the first 2 columns. I know I could specify a padding on the .item
class and set the flex prop to flex-start
but I can't always be 100% sure of the size the padding should be as it's scaling for multiple devices.
This can be demonstrated like so:
.container {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
border: 1px solid red;
}
.item {
flex: 0 0 16%; /*6 items per line leaving some for padding*/
border: 1px solid black;
box-sizing: border-box;
margin-right: 0.66%
}
<div class="container">
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
</div>
The overall spacing of the items between the red border isn't right and again, without knowing specific values, I don't know how I can set it to be so.
One can, as mentioned, add ghost elements to fill the last row, but in this case, one doesn't need to pollute the markup with unused elements, just use the nth-child
selector and simply calculate the needed left margin on all items but the first in each row.
The calculation is done by remove the sum of the items width (16% * 6))
from the parent's full width (100% -
, and then divide what's left with the amount of gaps / 5)
.item:not(:nth-child(6n+1))
will select all items but every 6th, starting from the 1st (e.g. 1st, 7th, 13th, and so on).
If the item count in each row will change, use a media query to adjust the 6n+1
selector and calculation values.
Stack snippet
.container {
display: flex;
flex-wrap: wrap;
width: 100%;
border: 1px solid red;
}
.item {
flex: 0 0 16%; /*6 items per line leaving some for margin*/
border: 1px solid black;
box-sizing: border-box;
}
.item:not(:nth-child(6n+1)) {
margin-left: calc( (100% - (16% * 6)) / 5 ); /* added */
}
<div class="container">
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
</div>
Unfortunately this is the limitation of flex
Work around
You can add empty flex items so that each row always have 6 (or n number) of items. It's extra html however this avoids you setting margins at different width for responsive design.
<div class="container">
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item">ITEM</div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
in your media query ranges you can define different width for your items and create a hide item class so that at that width it will be hidden.
An example from my work
we have a 12 column grid for large
and medium
, 6 column grid for small
and 4 columns for phone
. it's using a Freemarker macro but this is just to show you how to set it up, the below represents 1 row on any width that we support
<div class="<@grid large="1" medium="11" small="5" phone="0" />"></div>
<div class="<@grid large="11" medium="1" small="1" phone="4" />"></div>
The final output of the above is
<div class="large-col-1 medium-col-11 small-col-5 phone-col-0"></div>
<div class="large-col-1 medium-col-1 small-col-1 phone-col-4"></div>
Each of these classes are defined within their own media query range only.
You could use css grid to solve this but check browser support first
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With