Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-align] behaviour for width or flex-basis of flex items when gap applied to flex container #2668

Closed
gavinmcfarland opened this issue May 10, 2018 · 8 comments

Comments

@gavinmcfarland
Copy link

gavinmcfarland commented May 10, 2018

Hi. Are there any details around what affect of the proposed gap properties for flex containers might have on width or flex-basis if any? With CSS grid layout the author can use the span value but flex items have no concept of columns so I'm wondering how an author might specify the width/span of a flex item and account for the gutters/gap also?

@tabatkins
Copy link
Member

On flexboxes the gap is between flex items and rows. There's no gap "inside of" flex items; this is different from Grid.

@gavinmcfarland
Copy link
Author

It is really frustrating to talking to you. Do you ever stop to consider what someone might be trying to say before coming to your conclusions?

I meant what effect does the gap property have on flex items when applied to a container. How does one account for the gap when calculating the width of the flex items?

@gavinmcfarland
Copy link
Author

Here's an example.

If I do this

.container {
    display: flex;
    flex-wrap: nowrap;
    gap: 10px;
}

.item {
    width: 50%; /* or flex-basis*/
}

Does this mean that the flex items will not sit on one line because the gap would push them onto two lines?

There is no clarification in the spec that I can find that explains what happens in this scenario. Grid is a different concept to flex as in it sets up a template grid on the container and the author can specify where items should line up on that grid. Flex doesn't have the same concept and so there is no way I can think of for the author to accommodate the gaps unless the width or flex-basis automatically accounts for the gap, or there is another way to accommodate for them.

@tabatkins
Copy link
Member

tabatkins commented May 11, 2018

It is really frustrating to talking to you. Do you ever stop to consider what someone might be trying to say before coming to your conclusions?

Apologies for any perceived rudeness. Your question was asking about span, which doesn't carry over to Flexbox. The expanded details in your subsequent comment make your question much clearer. ^_^

The details of gap on flex containers are defined in https://drafts.csswg.org/css-align/#gap-flex. In particular, gap has no effect on how %s resolve - a width: 50% still resolves to 50% of the flex container's inner width. That means that two width: 50% items will not fit on a single line if there's a non-zero gap. (In your particular example, they'll just overflow slightly, since the container is nowrap.)

If you're using % widths, tho, you generally already know how many items fit on a line, and can use margins to produce gaps on your own (and make sure that, for example, all the %s add up to 100%). gap is more useful when you have fixed-size items in a container of unknown width, or flexible items, because you don't know where the line-break will occur, and so can't target your margins appropriately. (If you use margin-right for the separation, for example, you need to not apply it to the last item on the line, so it's flush with the edge.)

@gavinmcfarland
Copy link
Author

It's ok. It just makes me feel like I don't know what I'm talking about and I felt like I was waisting your time. I hope my reply didn't come across too impolite either.

You're right in my example, it will make the items push out further than the width of the container. I meant to put wrap in my head but put nowrap instead, hectic day I guess.

It's fine if the proposal is that gap has no effect on how %s resolve although I think we might be missing out on allowing authors the control they need. One advantage flex has over grid is that it's content can influence the layout. Setting a width on the items inside the flex container can change the overall layout, especially if wrap is enabled. With CSS grid this is not possible because each item's width cannot effect one another from what I'm understand.

One use case is if you wanted to have the contents of the flex container dictate their own sizes and therefore effect the layout of the whole container. This can be useful for layouts where the size of the content is important. Flex items can be added and removed and will allow content to adapt as needed because it is fluid. As a designer I would want this content to align to a grid with columns and gutters and it would be annoying to have to minus the gap from the width for it to line up correctly.

Also does flex-basis work on the basis that it takes up the available space

This brings me to my next point which is why don't we allow gap to work on any block or inline-block element? I don't see why gap has to be specific to flex and grid. It's a very useful property that millions of designers have had to contend without for years by using negative margin's to simulate gutters. You can use :first-child or :last-child selector to turn the margin of the first or last item off but when designing for responsive this is a pain because the margin is visible when the items run onto two rows.

I started working on a PostCSS plugin a while ago that tries to help with creating gutters and then that's when I saw that there was a proposal to allow the gap property to work for flex boxes also. Now I'm considering changing it to be more inline with the draft spec so that it could maybe be useful as a polyfill. It would be good to get your eyes on it as I'd like it to adhere to the spec as close as I can. It works with nested containers which I found an interesting challenge when it came to mixing containers with gaps in pixels and gaps in percentages. Would love to get your thoughts.

@tabatkins
Copy link
Member

With CSS grid this is not possible because each item's width cannot effect one another from what I'm understand.

Correct, but that underlines the other big difference between Flexbox and Grid - the width of a grid item has no effect on which row it ends up on, only the span does. Thus if the space is reduced by gap, that's fine, everything still sits in the same place. Flexbox is the exact opposite - the width is the only thing that determines which row its in, so adding a gap can change the row of some of the items.

This is why taking the gap into account when calculating %s on flex items is hard — the number of gaps affects the space available, but the space available can affect how many items will fit on the row, which affects how many gaps there will be. (It's not impossible to resolve this — we solve the exact same problem for ::first-line — but it's awkward and weird and we'd prefer to avoid it unless absolutely necessary.)

As a designer I would want this content to align to a grid with columns and gutters and it would be annoying to have to minus the gap from the width for it to line up correctly.

Trying to get a multiline flexbox to act like a grid is always going to be problematic. You can sometimes do it, but it'll always be somewhat fragile and hacky; it's not what the layout mode is designed to do. You should really be using Grid for this.

It sounds like you might be asking for "make this grid item automatically get an appropriate span, according to its size", which is tracked in #1373.

This brings me to my next point which is why don't we allow gap to work on any block or inline-block element?

The most straightforward answer is "because margin-collapsing is already complicated enough". Flex items, grid items, and multicol columns don't have collapsing margins; their margin boxes are treated as inviolate and don't overlap by default. Thus it's easy to put a gap between those margin boxes. Blocks don't behave this way — they collapse adjacent margins together, so there's no good notion of "between" where we could place the gaps.

We could disable margin collapsing when you use gaps, perhaps, but that would be relatively disruptive. Margins generally work fine, as blocks are single-line. The one place they're awkward is when the container has border/padding, and so the first and last children's margins can't collapse outside of the container; you then have to manually target them and set their top/bottom margin to 0. This is the exact problem that gap was designed to solve. ^_^ But there's a long-planned workaround that makes this work without disrupting current margin-collapsing behavior, tracked at https://wiki.csswg.org/ideas/margin-collapsing - automatically discard the margins of the first/last children, so they fit snugly into the container.

For inlines, we already have a property that's basically identical to gap - word-spacing. For example:

<!DOCTYPE html>
<div class=one><span>foo foo</span> <span>bar bar</span> <span>baz baz</span> <span>qux qux</span></div>
<div class=two><span>foo foo</span> <span>bar bar</span> <span>baz baz</span> <span>qux qux</span></div>
<style>
div { word-spacing: 1em; border: thin dotted; margin: 5px; }
div.two { width: 200px; }
span { display: inline-block; word-spacing: normal; }
</style>

Here, we use word-spacing to create a "gap" of 1em between the spans, which works properly when the text wraps (no annoying gap at the beginning or end of the lines). We just have to be careful because the property inherits, so you need to reset it to normal on the spans themselves.

@gavinmcfarland
Copy link
Author

It sounds like you might be asking for "make this grid item automatically get an appropriate span, according to its size", which is tracked in #1373.

Yes I think this would solve that use case.

But there's a long-planned workaround that makes this work without disrupting current margin-collapsing behavior, tracked at https://wiki.csswg.org/ideas/margin-collapsing - automatically discard the margins of the first/last children, so they fit snugly into the container.

Yes the margin-break would be a life saver especially because this would be extremely useful for responsive designs where the same elements might no longer fit on one line when less space is available. In fact if there was margin-break: element; that would be extremely useful if element queries ever come to fruition because the width of containers will always be unpredictable.

@gavinmcfarland
Copy link
Author

Actually there is one scenario I don't think issue #1373 will solve. That is when the designer is best to dictate the number of columns a item should span rather than the length/amount of text dictating it but they are unaware of what content will be sat either side of the item.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants