flex or grid columns based on (modulo) number of Items
So, I'm on a CMS / frontend where the content team can add a collection of cards (like: this is our contact team, these are our sponsors, ...).
These cards are listed by default with max 4 cards in a row. Then the next ones in the next row.
Now, here comes the problem:
It looks WAY better when if you've got 5 items you don't show 4 in the first row and just 1 in the last. But display 3 in the first one and 2 in the last.
Same for 13 items (4,4,3,2) - that's why modulo in the topic .
Is there a way to solve this CSS only (at least 2 items in a row) or if not (what I guess) - how would you create the JS and CSS setup (I'm using Vue, I know the numbers of items and can dynamically assign classes based on the modulo).
Currently the content team create different collections (a 3 items one and a 2 one) to archive this - but this is not a nice solution.
I'm currently thinking of: const rest = items.length % 4
if rest !== 1 -> everything is fine
if rest === 1 -> create a second list, where 2 items spliced from the original one and display them in a new flexed <div>
3 Replies
Are you willing to use
:has()
as a progressive enhancement, and people on older browsers get the sort of ugly grids?
If so, you can do it with CSS only. If not, then you'd have to use JS.
If you don't mind using :has()
, then you can do something like this:
And just to add some weight to this solution, :has()
support is at 87% now... https://caniuse.com/css-has
Only issue with the above solution is it just goes to a 1 column layout as a fallback, might be better to have a 3 column layout as a fallback or something?@bibamann I did experiment with something similar for someone else on this server. How to avoid orphans in flexbox/grid. Not the cleanest code (I'm more a designer than a coder 😅 ), for same width elements:
https://codepen.io/petpeeve/pen/abaRvNj
Variable width elements:
https://codepen.io/petpeeve/pen/MWqPjyz
But I think your requirement is much simpler?
@Kevin Thanks, I'll try this out tomorrow! I definitely need a dynamic solution like the "child count is divisible by ..." one. And the CSS only solution doesn't look like the nightmare I expected 😉
@phyrasaur yea, that's somehow my first thought, working with JS using modulo (with the difference of assigning different css classes instead of creating 2 lists). I'll come back on this if Kevins solution doesn't work. But also big thanks!
@Kevin "Only issue with the above solution is it just goes to a 1 column layout as a fallback, might be better to have a 3 column layout as a fallback or something?" - I'll see tomorrow
@Kevin Well, your solution just gives me 4 or 3 column grid layouts which wasn't what I wanted.
However here the solution with some js calculating a
grid-column-end
as I also needed to center the cards
I just did the 3-2 separation for exact 5 elements as for more it looked too much like a reversed pyramid (4-3-2).
Here the Vue file (I guess still easy to read / resuse in plain js)