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
phyrasaur
phyrasaur•15mo ago
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.
Jacord
Jacord•15mo ago
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.
Jacord
Jacord•15mo ago
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.
phyrasaur
phyrasaur•15mo ago
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?
Jacord
Jacord•15mo ago
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.
phyrasaur
phyrasaur•15mo ago
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
Jacord
Jacord•15mo ago
Yeah... that could work... I was also thinking of using content query units somehow.
phyrasaur
phyrasaur•15mo ago
I don't use margin, I add a pseudoelement to break the last two lines: https://codepen.io/petpeeve/pen/abaRvNj
phyrasaur
phyrasaur•15mo ago
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 index
Jacord
Jacord•15mo ago
That's beautiful thanks: Here's as far as I got with content queries
phyrasaur
phyrasaur•15mo ago
Using just css, you're still limited by the number of times you will write the nth-child, right?
Jacord
Jacord•15mo ago
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.
phyrasaur
phyrasaur•15mo ago
flexbox with variable width of flex-items https://codepen.io/petpeeve/pen/MWqPjyz
phyrasaur
phyrasaur•15mo ago
I should probably add a rAF to calculate layout thrashing stuff in one go, but uh maybe later <:hide_the_pain:982037703573000302>
Jacord
Jacord•15mo ago
This is excellent, you get a raise! 💵💵💵💵💵💵💵💵💵💵