15

Let's say I have a list of users, and each user has some number attached to it. Each user is listed like so:

<span><a href="/user/Niet">Niet</a> &rArr; 2</span>

They are all styled with:

.userlist>span {
    display: inline-block;
    padding: 2px 6px;
    border: 1px solid currentColor;
}

Here's an example of it in action:

Screenshot example

Okay, this looks all right, the list of users can get quite long so compact-ness is important here. My issue is that that right edge is horribly inconsistent, so I'm wondering if there's any way to improve that.

My first thought was, of course, just setting a fixed width on the spans. However username widths aren't exactly predictable. You can have someone called iiiii and someone called WWWWW but since this isn't a monospace font you get "iiiii" and "WWWWW", very clearly different widths there. So the "max width" would basically be the widest allowed character, which is W, multiplied by the max username length. Let's try that...

Fixed width

Ew. I might as well use a <ul> if that's the result I'm going to get. The next thought was maybe something involving display:table to have the widths be consistent across columns, while still remaining dynamic and - assuming most people have sensible usernames (*cough*... oh hey, so that's how you escape Markdown... huh...) - but it does tend to end up with a lot empty space still.

So my current idea is some kind of justify-alignment. That works quite well for text, right? But alas, text-align: justify does precisely bugger all in this case, possibly because there are no spaces between the elements to be justified.

My final attempt was using flexbox, something I'm already using to good effect in the site's new design. Let's see how it looks with display: flex; flex-wrap: wrap; on the container, and flex: 1 0 auto; on the elements...

Flexbox

Huh, that doesn't look too bad. Not too bad at al-

Fail

... Hm. So close. What I'd really like is for the last line of elements to not get flex stretched all the way across. It's okay when there's three or four on the last line, but two looks a bit silly and just one fills the whole width and looks ridiculous.

So I guess this whole little adventure boils down to one simple question:

How can I achieve justify-align-like behaviour, in which elements are spaced to use the full width of the container, except on the last line where they should use their natural width?


To complete this little story, thanks to @Michael_B's answer, here's how I've implemented the solution:

.userlist:after {
    content: '';
    flex: 10 0 auto;
}

And the result:

Result!!

Beautiful.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • 1
    The problem with `:after { flex: 10 0 auto; }` is that if you have the correct number in the last row it messes it up. Need to only apply if you have dangling items in last row. – chovy Mar 19 '16 at 22:56
  • @chovy While true, I think it's acceptable. The result is just like `text-align:justify` which is cool. – Niet the Dark Absol Mar 20 '16 at 11:05

1 Answers1

17

Using flexbox, create 3 or 4 "phantom" items that always occupy the last slots.

So, for instance, user #82 is currently your last entry.

Make fake users 83, 84, 85 with visibility: hidden.

Alternatively, try just one phantom item at the end with visibility: hidden and flex-grow: 10. Target it with :last-child or :last-of-type pseudo-class.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 2
    Holy crap that's neat, and it even works if I use the `::after` pseudo-element. Nice! – Niet the Dark Absol Jan 21 '16 at 17:47
  • 1
    I've added a screenshot of the result of implementing your solution to the end of my question so it can be seen. Thank you so much for this idea! – Niet the Dark Absol Jan 21 '16 at 17:52
  • 1
    As an expansion of the second alternative, this phantom item can be a pseudo of the container. You don't need to alter the DOM, and you can target it directly instead of using last-child – vals Jun 17 '16 at 07:49
  • using an :after on parent ignores your spaces between, while you can't create more elements based on :last-child:nth-child(n+...) as they would nest in children... Anyway with the "right" count of phantom elements, it wouldn't be responsive... – Fanky Oct 02 '19 at 07:24