w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.43k stars 656 forks source link

[css-flexbox] Proposal: max flex grow #4143

Open benface opened 5 years ago

benface commented 5 years ago

Problem

Look at this Codepen: https://codepen.io/benface/pen/EqPxwB

If there's enough horizontal space, I would like the links to grow in width but only up to a certain amount (40 more pixels). So on a mobile device they would stay the same, but on a large screen they would be slightly wider, like this:

max-flex-grow

Possible solutions

too-wide

unequal-gaps

Proposed solution

A new flex-max-grow (or max-flex-grow, or even flex-grow-max?) property that defines how much a flex item is allowed to grow:

.link {
  flex-grow: 1;
  flex-max-grow: 40px;
}
jonjohnjohnson commented 5 years ago

a different amount of pixels has been added to each link because they have different default widths, which results in unequal gaps

Are you mostly trying to work around having a responsive but uniform "padding" between items? If this is the case, "maxing" flex grow, which keys off a fraction of the empty space in the flex direction and the content size of the item, might not be the way to go, because short of that max, the grow will still be related to the unique size of content in each item?

Even if min()/max() hasn't landed everywhere yet, I think your best bet with currently specified behavior would be to use them in ways like adding padding: 10px max(10px, 3%) on your flex items. Though I know the 3% or whatever amount of %/vw would have to be related to the amount of flex items.

benface commented 5 years ago

Are you mostly trying to work around having a responsive but uniform "padding" between items?

Yes.

If this is the case, "maxing" flex grow, which keys off a fraction of the empty space in the flex direction and the content size of the item, might not be the way to go, because short of that max, the grow will still be related to the unique size of content in each item?

Hmm, but if the value of flex-grow is the same for all items (e.g. 1), it is uniform. That is, if there are 4 items and the flex container gets wider by 4 pixels, each item grows by 1 pixel, which is the behaviour I want. Unless I'm misunderstanding what you're saying?

Even if min()/max() hasn't landed everywhere yet, I think your best bet with currently specified behavior would be to use them in ways like adding padding: 10px max(10px, 3%) on your flex items.

Yes, that would probably be a better solution than any of the "possible solutions" I tried above, thank you. Even better would be max(10px, min(3%, 30px)) (or clamp(10px, 3%, 30px)), but it's still not ideal:

  1. flex-grow makes the items grow as soon as there's available space (filling the container short of the max), whereas to get the same behaviour with padding, you would need to fine-tune the 3% value very precisely based on the total width + minimum padding of the flex items, and if you get it slightly wrong it could cause unwanted overflow / wrapping.

  2. Growing the padding instead of the content's width doesn't affect my use case so much, but imagine if the flex items were list items (<li>) instead, and they each contained a link (<a>), and you didn't want to have any gap between the links like in my example. The padding in the <li> would make that difficult / impossible.

tabatkins commented 5 years ago

I have an alternate solution for you: https://codepen.io/TabAtkins/pen/OKNPgE

The gist of it is that the nav is a grid, and each item is placed across three rows: minmax(10px, 40px) auto minmax(10px, 40px). The auto column will size to the item's width, then the "side" columns will grow from 10px to 40px, depending on available space, all at the same rate.

You do have to predict how many items you'll have, but that's it.

benface commented 5 years ago

@tabatkins Ok, yeah, that is a great solution! A bit annoying to have to use Grid for something that really sounds like it should be handled by Flexbox, but I'm OK with that solution if nobody feels like flex-max-grow would be a worthy addition.

benface commented 5 years ago

Wait, I spoke too soon! It looks like the gaps between the texts are not equal in your pen. Not sure why.

jonjohnjohnson commented 5 years ago

As far as @tabatkins grid demo goes, you must add white-space: nowrap; to the nav for equal spacing. Otherwise very long items will have less space around them.

Update The 10px min argument in the demo is mostly useless. To get the effect that @benface wants, you must put the 10px on something like the padding of the grid items.

Loirooriol commented 5 years ago

@jonjohnjohnson Instead of using white-space to increase the min-content contribution to equal the max-content one, I would replace auto with max-content in the grid template.

And yes, minmax(10px, 40px) is not that useful because of grid-column: span 3. With sibling-index() we could use something like grid-column: calc(3 * sibling-index() - 1)