Preventing Flexbox 'runts' with CSS
So on our website, we often have relatively long menus where flex-box is the ideal way to arrange a number of options. The only problem arises when the last item is all alone and it looks weird and unbalanced. We have avoided this in the past basically using 'magic numbers' as it were, but I'm working on a more general solution.
Here's my codepen: https://codepen.io/crowjake/pen/vYzzQxY
My solution is OK so far (custom properties and nth-of-type stuff), but is pretty restrictive and will require media/container queries to be made responsive, which somewhat defeats the point of flexbox.
Has anyone else managed this with pure CSS?
17 Replies
Not a solution, but looking at your codepen, I think you would prefer grid with auto-fill? Something like this, the strategy to target the runt is still similar anyway:
https://play.tailwindcss.com/AHhPyimFPF?file=css
Tailwind Play
Tailwind Play
An advanced online playground for Tailwind CSS that lets you use all of Tailwind's build-time features directly in the browser.
Thanks for trying!
This could be good if I can't find a better way to to do this with flexbox.
Although my codepen looks like a grid, I think that's more of an unintended consequence of my solution, not actually how I want it to look.
Preferably it would look exactly like a normal wrapped flex-box. With the only change being that there is a minimum number items in the last row, to be taken from the row above.
I am going to take a look at some masonry stuff.
Here's a tidier explanation of the kind of solution I have used: https://cssence.com/2020/prevent-orphan-in-flexbox/
Preventing Orphans in Flexbox
No single element in last row, thanks to :nth-last-child.
Ah okay. Btw, is the number of children are known before hand? Do you have to do this purely in CSS or you can use JS in the mix?
I am assuming the number of children is not known, so that my code can be reused.
I can actually use Javascript if I like.
I'm thinking of a ResizeObserver, calculate the number of item for the last 2 lines, average them but give the second last one the bigger number and then check index and apply/remove margin accordingly
Yeah... that could work... I was also thinking of using content query units somehow.
I don't use margin, I add a pseudoelement to break the last two lines:
https://codepen.io/petpeeve/pen/abaRvNj
resize event because I'm lazy <:hide_the_pain:982037703573000302>
so I set the
order
of flex items statically with css/class so that ::before
will always be between .breakem-second-last
and breakem-last
the js part: I get the custom props for basis and gap for calculation (you can manually calculate them with child.offsetWidth
and child.offsetLeft
). And then if the tail end is even number, I reduce the last line by 1, if it's odd, it will be the smaller number of the average. And then I iterate over each child to set the class according to its indexThat's beautiful thanks:
Here's as far as I got with content queries
Using just css, you're still limited by the number of times you will write the nth-child, right?
Exactly, there's no way for the 'nth' variable to 'know' how many items are on a line
I do think the use of a pseudo element could carry over pretty well though.
flexbox with variable width of flex-items
https://codepen.io/petpeeve/pen/MWqPjyz
I should probably add a rAF to calculate layout thrashing stuff in one go, but uh maybe later <:hide_the_pain:982037703573000302>
This is excellent, you get a raise! 💵💵💵💵💵💵💵💵💵💵